﻿using Oracle.DataAccess.Client;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Xml;

namespace MyCommon.DBUtility
{
    /// <summary>
    /// Oracle数据访问帮助类
    /// </summary>
    public sealed class OracleHelper
    {
        #region private utility methods & constructors

        //由于这个类仅仅可以提供静态的方法，采用默认的private构造器，可以不用创建new SqlHelper( )实例。
        //OracleParameter
        //

        private OracleHelper()
        {
        }

        /// <summary>
        ///     这个方法是用Sql命令给Sql参数数组赋值
        ///     这个方法将会给任何一个参数(包括输入/输出参数和null)赋DbNull值。
        ///     这种行为不会使用默认值，但是这样的话比起那些单纯的输出参数(源自输入/输出),在这里使用者不提供输入值，
        ///     它们将会有比较少的公共事件
        /// </summary>
        /// <param name="command">增加参数的命令</param>
        /// <param name="commandParameters">增加Sql参数数组的命令</param>
        private static void AttachParameters(OracleCommand command, OracleParameter[] commandParameters)
        {
            if (command == null) throw new ArgumentNullException("command");
            if (commandParameters != null)
            {
                foreach (OracleParameter p in commandParameters)
                {
                    if (p != null)
                    {
                        // Check for derived output value with no value assigned
                        // 检查一下源自没有赋给值的输出值
                        if ((p.Direction == ParameterDirection.InputOutput ||
                             p.Direction == ParameterDirection.Input) &&
                            (p.Value == null))
                        {
                            p.Value = DBNull.Value;
                        }
                        command.Parameters.Add(p);
                    }
                }
            }
        }

        /// <summary>
        ///     这个方法把数据行列的值赋给Sql参数数组
        /// </summary>
        /// <param name="commandParameters">被赋值的Sql参数数组</param>
        /// <param name="dataRow">拥有存储过程参数值的数据行</param>
        private static void AssignParameterValues(OracleParameter[] commandParameters, DataRow dataRow)
        {
            if ((commandParameters == null) || (dataRow == null))
            {
                // Do nothing if we get no data
                // 如果我们没有得到数据，就什么也不做
                return;
            }

            int i = 0;
            // Set the parameters values
            // 给参数赋值
            foreach (OracleParameter commandParameter in commandParameters)
            {
                // Check the parameter name
                // 检查参数的名字
                if (commandParameter.ParameterName == null ||
                    commandParameter.ParameterName.Length <= 1)
                    throw new Exception(
                        string.Format(
                            "Please provide a valid parameter name on the parameter #{0}, the ParameterName property has the following value: '{1}'.",
                            i, commandParameter.ParameterName));
                if (dataRow.Table.Columns.IndexOf(commandParameter.ParameterName.Substring(1)) != -1)
                    commandParameter.Value = dataRow[commandParameter.ParameterName.Substring(1)];
                i++;
            }
        }

        /// <summary>
        ///     这个方法通过数组的形式把值赋给Sql参数
        /// </summary>
        /// <param name="commandParameters">给Sql参数数组赋值</param>
        /// <param name="parameterValues">拥有赋给值的对象数组</param>
        private static void AssignParameterValues(OracleParameter[] commandParameters, object[] parameterValues)
        {
            if ((commandParameters == null) || (parameterValues == null))
            {
                // Do nothing if we get no data
                // 如果我们没有得到数据就什么也不做
                return;
            }

            // We must have the same number of values as we pave parameters to put them in
            // 当我们有要提交的参数时，参数的个数必需一样
            if (commandParameters.Length != parameterValues.Length)
            {
                throw new ArgumentException("Parameter count does not match Parameter Value count.");
            }

            // Iterate through the OracleParameters, assigning the values from the corresponding position in the 
            // value array
            // 通过Sql参数重述一下，在存放值的数组中的恰当位置给值赋值
            for (int i = 0, j = commandParameters.Length; i < j; i++)
            {
                // If the current array value derives from IDbDataParameter, then assign its Value property
                // 如果目前的参数值是从IDbDataParameter得来的，那么给它们赋上值的属性
                if (parameterValues[i] is IDbDataParameter)
                {
                    var paramInstance = (IDbDataParameter)parameterValues[i];
                    if (paramInstance.Value == null)
                    {
                        commandParameters[i].Value = DBNull.Value;
                    }
                    else
                    {
                        commandParameters[i].Value = paramInstance.Value;
                    }
                }
                else if (parameterValues[i] == null)
                {
                    commandParameters[i].Value = DBNull.Value;
                }
                else
                {
                    commandParameters[i].Value = parameterValues[i];
                }
            }
        }


        /// <summary>
        ///     这个方法打开一个连接，事务，命令类型和由命令提供的参数并给它们赋值(如果需要的话)
        /// </summary>
        /// <param name="command">准备的Sql命令</param>
        /// <param name="connection">一个有效的执行命令的Sql连接</param>
        /// <param name="transaction">一个有效的Sql事务或者NULL值</param>
        /// <param name="commandType">命令类型(存储过程，文本，等）</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令。</param>
        /// <param name="commandParameters">用命令来给这个Sql参数赋值或者没有参数提供，那它就是NULL值</param>
        /// <param name="mustCloseConnection">
        ///     <c>true</c> 通过方法把连接打开,否则是false
        /// </param>
        private static void PrepareCommand(OracleCommand command, OracleConnection connection,
                                           OracleTransaction transaction, CommandType commandType, string commandText,
                                           OracleParameter[] commandParameters, out bool mustCloseConnection)
        {
            if (command == null) throw new ArgumentNullException("command");
            if (commandText == null || commandText.Length == 0) throw new ArgumentNullException("commandText");

            // If the provided connection is not open, we will open it
            // 如果提供的连接没有打开，我们把它打开
            if (connection.State != ConnectionState.Open)
            {
                mustCloseConnection = true;
                connection.Open();
            }
            else
            {
                mustCloseConnection = false;
            }

            // Associate the connection with the command
            // 用命令来连接
            command.Connection = connection;

            // Set the command text (stored procedure name or SQL statement)
            // 设置命令文本(存储过程名或者SQL状态
            command.CommandText = commandText;

            // If we were provided a transaction, assign it
            // 如果提供我们一个事务，给它赋值
            if (transaction != null)
            {
                if (transaction.Connection == null)
                    throw new ArgumentException(
                        "The transaction was rollbacked or commited, please provide an open transaction.", "transaction");
                // command.Transaction = transaction;
            }

            // Set the command type
            // 设置命令类型
            command.CommandType = commandType;

            // Attach the command parameters if they are provided
            // 如果它们被提供，就赋上命令参数
            if (commandParameters != null)
            {
                AttachParameters(command, commandParameters);
            }
            return;
        }

        /// <summary>
        ///     这个方法打开一个连接，事务，命令类型和由命令提供的参数并给它们赋值(如果需要的话)
        /// </summary>
        /// <param name="command">准备的Sql命令</param>
        /// <param name="connection">一个有效的执行命令的Sql连接</param>
        /// <param name="transaction">一个有效的Sql事务或者NULL值</param>
        /// <param name="commandType">命令类型(存储过程，文本，等）</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令。</param>
        /// <param name="commandParameters">用命令来给这个Sql参数赋值或者没有参数提供，那它就是NULL值</param>
        /// <param name="mustCloseConnection">
        ///     <c>true</c> 通过方法把连接打开,否则是false
        /// </param>
        private static void PrepareCommand(OracleCommand command, OracleConnection connection,
                                           OracleTransaction transaction, CommandType commandType, string commandText,
                                           int commandTimeout, OracleParameter[] commandParameters,
                                           out bool mustCloseConnection)
        {
            if (command == null) throw new ArgumentNullException("command");
            if (commandText == null || commandText.Length == 0) throw new ArgumentNullException("commandText");

            // If the provided connection is not open, we will open it
            // 如果提供的连接没有打开，我们把它打开
            if (connection.State != ConnectionState.Open)
            {
                mustCloseConnection = true;
                connection.Open();
            }
            else
            {
                mustCloseConnection = false;
            }

            // Associate the connection with the command
            // 用命令来连接
            command.Connection = connection;

            // Set the command text (stored procedure name or SQL statement)
            // 设置命令文本(存储过程名或者SQL状态
            command.CommandText = commandText;

            // If we were provided a transaction, assign it
            // 如果提供我们一个事务，给它赋值
            if (transaction != null)
            {
                if (transaction.Connection == null)
                    throw new ArgumentException(
                        "The transaction was rollbacked or commited, please provide an open transaction.", "transaction");
                //   command.Transaction = transaction;
            }

            // Set the command type
            // 设置命令类型
            command.CommandType = commandType;

            //设置命令执行错误返回等待的时间秒数
            if (!(commandTimeout < 0))
            {
                command.CommandTimeout = commandTimeout;
            }

            // Attach the command parameters if they are provided
            // 如果它们被提供，就赋上命令参数
            if (commandParameters != null)
            {
                AttachParameters(command, commandParameters);
            }
            return;
        }

        #endregion private utility methods & constructors

        #region ExecuteNonQuery

        /// <summary>
        ///     执行一个Sql命令(不返回结果集合并且不返回参数),这个命令是依附于指定了连接字符串的数据库
        /// </summary>
        /// <param name="connectionString">一个有效的Sql连接字符串</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令</param>
        /// <returns>受命令影响的行数(整型)</returns>
        public static int ExecuteNonQuery(string connectionString, CommandType commandType, string commandText)
        {
            // Pass through the call providing null for the set of OracleParameters
            // 通过一个为Sql参数提供null值的调用
            return ExecuteNonQuery(connectionString, commandType, commandText, null);
        }

        /// <summary>
        ///     使用提供的参数执行一个Sql命令(不返回结果集合),这个命令是依附于指定了连接字符串的数据库
        /// </summary>
        /// <param name="connectionString">一个有效的Sql连接字符串</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令</param>
        /// <param name="commandParameters">用于执行命令的Sql参数数组</param>
        /// <returns>受命令影响的行数(整型)</returns>
        public static int ExecuteNonQuery(string connectionString, CommandType commandType, string commandText,
                                          params OracleParameter[] commandParameters)
        {
            if (connectionString == null || connectionString.Length == 0)
                throw new ArgumentNullException("connectionString");

            // Create & open a OracleConnection, and dispose of it after we are done
            // 创建和打开sql连接，不用时把它释放掉

            using (var connection = new OracleConnection(connectionString))
            {
                connection.Open();

                // Call the overload that takes a connection in place of the connection string
                // 调用这个在连接字符串中截取适当连接字符串的overload  
                return ExecuteNonQuery(connection, commandType, commandText, commandParameters);
            }
        }

        /// <summary>
        /// 执行不返回结果的Sql
        /// </summary>
        /// <param name="cmdText">Sql命令</param>
        /// <param name="connectionString">连接字符串</param>
        [Obsolete("该方法不建议使用，请使用ExecuteNonQuery方法的重载！")]
        public static void ExecuteSql(string cmdText, string connectionString)
        {
            using (var conn = new OracleConnection(connectionString))
            {
                var cmd = new OracleCommand(cmdText, conn);
                conn.Open();
                cmd.ExecuteNonQuery();
                conn.Close();
            }
        }

        /// <summary>
        ///     通过一个返回结果集合的sql命令(不返回结果集合)来执行一个提供了参数值的存储过程，针对指定的Sql事务。
        ///     这个方法为了发现存储过程(每一个存储过程第一次被调用)的参数，它将会查询数据库并且按照参数顺序给参数赋值。
        /// </summary>
        /// <param name="connectionString">一个有效的Sql连接字符串</param>
        /// <param name="spName">存储过程的名字</param>
        /// <param name="parameterValues">存储过程输入的值赋给这个对象数组</param>
        /// <returns>受命令影响的行数(整型)</returns>
        public static int ExecuteNonQuery(string connectionString, string spName, params object[] parameterValues)
        {
            if (connectionString == null || connectionString.Length == 0)
                throw new ArgumentNullException("connectionString");
            if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");

            // If we receive parameter values, we need to figure out where they go
            // 如果我们接受到参数值，我们需要知道它们来自那里

            if ((parameterValues != null) && (parameterValues.Length > 0))
            {
                // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
                // 从存放着参数的缓存器中填充这个存储过程的参数
                OracleParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connectionString, spName);

                // Assign the provided values to these parameters based on parameter order
                // 按参数顺序给这些参数赋值
                AssignParameterValues(commandParameters, parameterValues);

                // Call the overload that takes an array of OracleParameters
                // 调用接受Sql参数数组的overload

                return ExecuteNonQuery(connectionString, CommandType.StoredProcedure, spName, commandParameters);
            }
            else
            {
                // Otherwise we can just call the SP without params
                // 否则，我们只能调用没有参数的SP
                return ExecuteNonQuery(connectionString, CommandType.StoredProcedure, spName);
            }
        }

        /// <summary>
        ///     执行一个Sql命令(不返回结果集合并且不返回参数),这个命令是依附于提供的SQL事务
        /// </summary>
        /// <param name="connection">一个有效的Sql连接</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令</param>
        /// <returns>受命令影响的行数(整型)</returns>
        public static int ExecuteNonQuery(OracleConnection connection, CommandType commandType, string commandText)
        {
            // Pass through the call providing null for the set of OracleParameters
            // 通过一个为Sql参数提供null值的调用

            return ExecuteNonQuery(connection, commandType, commandText, null);
        }

        /// <summary>
        ///     执行一个Sql命令(不返回结果集合)，针对这个指定的Sql连接
        /// </summary>
        /// <param name="connection">一个有效的Sql连接</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令)</param>
        /// <param name="commandParameters">用于执行命令的Sql参数数组</param>
        /// <returns>受命令影响的行数(整型)</returns>
        public static int ExecuteNonQuery(OracleConnection connection, CommandType commandType, string commandText,
                                          params OracleParameter[] commandParameters)
        {
            if (connection == null) throw new ArgumentNullException("connection");

            // Create a command and prepare it for execution
            // 创建一个准备执行的命令
            var cmd = new OracleCommand();
            bool mustCloseConnection = false;
            PrepareCommand(cmd, connection, null, commandType, commandText, commandParameters, out mustCloseConnection);

            // Finally, execute the command
            // 最后，执行命令
            int retval = cmd.ExecuteNonQuery();

            // Detach the OracleParameters from the command object, so they can be used again
            // 从命令对象中分离sql参数，以便于它们可以被再次使用
            cmd.Parameters.Clear();
            if (mustCloseConnection)
                connection.Close();
            return retval;
        }

        /// <summary>
        ///     通过一个返回结果集合的sql命令来(不返回结果集合)执行一个提供了参数值的存储过程，针对指定的Sql连接。
        ///     这个方法为了发现存储过程(每一个存储过程第一次被调用)的参数，它将会查询数据库并且按照参数顺序给参数赋值。
        /// </summary>
        /// <param name="connection">一个有效的Sql连接</param>
        /// <param name="spName">存储过程的名字</param>
        /// <param name="parameterValues">存储过程输入的值赋给这个对象数组</param>
        /// <returns>受命令影响的行数(整型)</returns>
        public static int ExecuteNonQuery(OracleConnection connection, string spName, params object[] parameterValues)
        {
            if (connection == null) throw new ArgumentNullException("connection");
            if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");

            // If we receive parameter values, we need to figure out where they go
            // 如果我们接受到参数值，我们需要知道它们来自那里
            if ((parameterValues != null) && (parameterValues.Length > 0))
            {
                // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
                // 从存放着参数的缓存器中填充这个存储过程的参数
                OracleParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connection, spName);

                // Assign the provided values to these parameters based on parameter order
                // 按参数顺序给这些参数赋值
                AssignParameterValues(commandParameters, parameterValues);

                // Call the overload that takes an array of OracleParameters
                // 调用接受Sql参数数组的overload


                return ExecuteNonQuery(connection, CommandType.StoredProcedure, spName, commandParameters);
            }
            else
            {
                // Otherwise we can just call the SP without params
                // 否则，我们只能调用没有参数的SP
                return ExecuteNonQuery(connection, CommandType.StoredProcedure, spName);
            }
        }

        /// <summary>
        ///     执行一个Sql命令(不返回结果集合并且不返回参数),这个命令是依附于提供的SQL事务
        /// </summary>
        /// <param name="transaction">一个有效的事务</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令</param>
        /// <returns>受命令影响的行数(整型)</returns>
        public static int ExecuteNonQuery(OracleTransaction transaction, CommandType commandType, string commandText)
        {
            // Pass through the call providing null for the set of OracleParameters
            // 通过一个为Sql参数提供null值的调用
            return ExecuteNonQuery(transaction, commandType, commandText, null);
        }

        /// <summary>
        ///     执行一个Sql命令(不返回结果集合),这个命令是依附于指定了连接字符串的数据库
        /// </summary>
        /// <param name="transaction">一个有效的事务</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令</param>
        /// <param name="commandParameters">用于执行命令的Sql参数数组</param>
        /// <returns>受命令影响的行数(整型)</returns>
        public static int ExecuteNonQuery(OracleTransaction transaction, CommandType commandType, string commandText,
                                          params OracleParameter[] commandParameters)
        {
            if (transaction == null) throw new ArgumentNullException("transaction");
            if (transaction != null && transaction.Connection == null)
                throw new ArgumentException(
                    "The transaction was rollbacked or commited, please provide an open transaction.", "transaction");

            // Create a command and prepare it for execution
            // 创建一个准备执行的命令
            var cmd = new OracleCommand();
            bool mustCloseConnection = false;
            PrepareCommand(cmd, transaction.Connection, transaction, commandType, commandText, commandParameters,
                           out mustCloseConnection);

            // Finally, execute the command
            // 最后，执行命令
            int retval = cmd.ExecuteNonQuery();

            // Detach the OracleParameters from the command object, so they can be used again
            // 从命令对象中分离sql参数，以便于它们可以被再次使用
            cmd.Parameters.Clear();
            return retval;
        }

        /// <summary>
        ///     通过一个返回一个结果集合的sql命令来执行一个提供了参数值的存储过程，针对指定的Sql事务。
        ///     这个方法为了发现存储过程(每一个存储过程第一次被调用)的参数，它将会查询数据库并且按照参数顺序给参数赋值。
        /// </summary>
        /// <param name="transaction">一个有效的sql事务</param>
        /// <param name="spName">存储过程的名字</param>
        /// <param name="parameterValues">存储过程输入的值赋给这个对象数组</param>
        /// <returns>受命令影响的行数(整型)</returns>
        public static int ExecuteNonQuery(OracleTransaction transaction, string spName, params object[] parameterValues)
        {
            if (transaction == null) throw new ArgumentNullException("transaction");
            if (transaction != null && transaction.Connection == null)
                throw new ArgumentException(
                    "The transaction was rollbacked or commited, please provide an open transaction.", "transaction");
            if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");

            // If we receive parameter values, we need to figure out where they go
            // 如果我们接受到参数值，我们需要知道它们来自那里
            if ((parameterValues != null) && (parameterValues.Length > 0))
            {
                // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
                // 从存放着参数的缓存器中填充这个存储过程的参数

                OracleParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(transaction.Connection,
                                                                                                spName);

                // Assign the provided values to these parameters based on parameter order
                // 按参数顺序给这些参数赋值
                AssignParameterValues(commandParameters, parameterValues);

                // Call the overload that takes an array of OracleParameters
                // 调用接受Sql参数数组的overload

                return ExecuteNonQuery(transaction, CommandType.StoredProcedure, spName, commandParameters);
            }
            else
            {
                // Otherwise we can just call the SP without params
                // 否则，我们只能调用没有参数的SP
                return ExecuteNonQuery(transaction, CommandType.StoredProcedure, spName);
            }
        }

        /// <summary>
        ///     执行一个Sql命令(不返回结果集合并且不返回参数),这个命令是依附于指定了连接字符串的数据库
        /// </summary>
        /// <param name="connectionString">一个有效的Sql连接字符串</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <returns>受命令影响的行数(整型)</returns>
        public static int ExecuteNonQuery(string connectionString, CommandType commandType, string commandText,
                                          int commandTimeout)
        {
            // Pass through the call providing null for the set of OracleParameters
            // 通过一个为Sql参数提供null值的调用
            return ExecuteNonQuery(connectionString, commandType, commandText, commandTimeout, null);
        }


        /// <summary>
        ///     使用提供的参数执行一个Sql命令(不返回结果集合),这个命令是依附于指定了连接字符串的数据库
        /// </summary>
        /// <param name="connectionString">一个有效的Sql连接字符串</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <param name="commandParameters">用于执行命令的Sql参数数组</param>
        /// <returns>受命令影响的行数(整型)</returns>
        public static int ExecuteNonQuery(string connectionString, CommandType commandType, string commandText,
                                          int commandTimeout, params OracleParameter[] commandParameters)
        {
            if (connectionString == null || connectionString.Length == 0)
                throw new ArgumentNullException("connectionString");

            // Create & open a OracleConnection, and dispose of it after we are done
            // 创建和打开sql连接，不用时把它释放掉
            using (var connection = new OracleConnection(connectionString))
            {
                connection.Open();

                // Call the overload that takes a connection in place of the connection string
                // 调用这个在连接字符串中截取适当连接字符串的overload  
                return ExecuteNonQuery(connection, commandType, commandText, commandTimeout, commandParameters);
            }
        }

        /// <summary>
        ///     通过一个返回结果集合的sql命令(不返回结果集合)来执行一个提供了参数值的存储过程，针对指定的Sql事务。
        ///     这个方法为了发现存储过程(每一个存储过程第一次被调用)的参数，它将会查询数据库并且按照参数顺序给参数赋值。
        /// </summary>
        /// <param name="connectionString">一个有效的Sql连接字符串</param>
        /// <param name="spName">存储过程的名字</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <param name="parameterValues">存储过程输入的值赋给这个对象数组</param>
        /// <returns>受命令影响的行数(整型)</returns>
        public static int ExecuteNonQuery(string connectionString, string spName, int commandTimeout,
                                          params object[] parameterValues)
        {
            if (connectionString == null || connectionString.Length == 0)
                throw new ArgumentNullException("connectionString");
            if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");

            // If we receive parameter values, we need to figure out where they go
            // 如果我们接受到参数值，我们需要知道它们来自那里

            if ((parameterValues != null) && (parameterValues.Length > 0))
            {
                // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
                // 从存放着参数的缓存器中填充这个存储过程的参数
                OracleParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connectionString, spName);

                // Assign the provided values to these parameters based on parameter order
                // 按参数顺序给这些参数赋值
                AssignParameterValues(commandParameters, parameterValues);

                // Call the overload that takes an array of OracleParameters
                // 调用接受Sql参数数组的overload

                return ExecuteNonQuery(connectionString, CommandType.StoredProcedure, spName, commandTimeout,
                                       commandParameters);
            }
            else
            {
                // Otherwise we can just call the SP without params
                // 否则，我们只能调用没有参数的SP
                return ExecuteNonQuery(connectionString, CommandType.StoredProcedure, spName, commandTimeout);
            }
        }

        /// <summary>
        ///     执行一个Sql命令(不返回结果集合并且不返回参数),这个命令是依附于提供的SQL事务
        /// </summary>
        /// <param name="connection">一个有效的Sql连接</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <returns>受命令影响的行数(整型)</returns>
        public static int ExecuteNonQuery(OracleConnection connection, CommandType commandType, string commandText,
                                          int commandTimeout)
        {
            // Pass through the call providing null for the set of OracleParameters
            // 通过一个为Sql参数提供null值的调用

            return ExecuteNonQuery(connection, commandType, commandText, commandTimeout, null);
        }

        /// <summary>
        ///     执行一个Sql命令(不返回结果集合)，针对这个指定的Sql连接
        /// </summary>
        /// <param name="connection">一个有效的Sql连接</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令)</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <param name="commandParameters">用于执行命令的Sql参数数组</param>
        /// <returns>受命令影响的行数(整型)</returns>
        public static int ExecuteNonQuery(OracleConnection connection, CommandType commandType, string commandText,
                                          int commandTimeout, params OracleParameter[] commandParameters)
        {
            if (connection == null) throw new ArgumentNullException("connection");

            // Create a command and prepare it for execution
            // 创建一个准备执行的命令
            var cmd = new OracleCommand();
            bool mustCloseConnection = false;
            PrepareCommand(cmd, connection, null, commandType, commandText, commandTimeout, commandParameters,
                           out mustCloseConnection);

            // Finally, execute the command
            // 最后，执行命令
            int retval = cmd.ExecuteNonQuery();

            // Detach the OracleParameters from the command object, so they can be used again
            // 从命令对象中分离sql参数，以便于它们可以被再次使用
            cmd.Parameters.Clear();
            if (mustCloseConnection)
                connection.Close();
            return retval;
        }

        /// <summary>
        ///     通过一个返回结果集合的sql命令来(不返回结果集合)执行一个提供了参数值的存储过程，针对指定的Sql连接。
        ///     这个方法为了发现存储过程(每一个存储过程第一次被调用)的参数，它将会查询数据库并且按照参数顺序给参数赋值。
        /// </summary>
        /// <param name="connection">一个有效的Sql连接</param>
        /// <param name="spName">存储过程的名字</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <param name="parameterValues">存储过程输入的值赋给这个对象数组</param>
        /// <returns>受命令影响的行数(整型)</returns>
        public static int ExecuteNonQuery(OracleConnection connection, string spName, int commandTimeout,
                                          params object[] parameterValues)
        {
            if (connection == null) throw new ArgumentNullException("connection");
            if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");

            // If we receive parameter values, we need to figure out where they go
            // 如果我们接受到参数值，我们需要知道它们来自那里
            if ((parameterValues != null) && (parameterValues.Length > 0))
            {
                // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
                // 从存放着参数的缓存器中填充这个存储过程的参数
                OracleParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connection, spName);

                // Assign the provided values to these parameters based on parameter order
                // 按参数顺序给这些参数赋值
                AssignParameterValues(commandParameters, parameterValues);

                // Call the overload that takes an array of OracleParameters
                // 调用接受Sql参数数组的overload


                return ExecuteNonQuery(connection, CommandType.StoredProcedure, spName, commandTimeout,
                                       commandParameters);
            }
            else
            {
                // Otherwise we can just call the SP without params
                // 否则，我们只能调用没有参数的SP
                return ExecuteNonQuery(connection, CommandType.StoredProcedure, spName, commandTimeout);
            }
        }

        /// <summary>
        ///     执行一个Sql命令(不返回结果集合并且不返回参数),这个命令是依附于提供的SQL事务
        /// </summary>
        /// <param name="transaction">一个有效的事务</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <returns>受命令影响的行数(整型)</returns>
        public static int ExecuteNonQuery(OracleTransaction transaction, CommandType commandType, string commandText,
                                          int commandTimeout)
        {
            // Pass through the call providing null for the set of OracleParameters
            // 通过一个为Sql参数提供null值的调用
            return ExecuteNonQuery(transaction, commandType, commandText, commandTimeout, null);
        }

        /// <summary>
        ///     执行一个Sql命令(不返回结果集合),这个命令是依附于指定了连接字符串的数据库
        /// </summary>
        /// <param name="transaction">一个有效的事务</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <param name="commandParameters">用于执行命令的Sql参数数组</param>
        /// <returns>受命令影响的行数(整型)</returns>
        public static int ExecuteNonQuery(OracleTransaction transaction, CommandType commandType, string commandText,
                                          int commandTimeout, params OracleParameter[] commandParameters)
        {
            if (transaction == null) throw new ArgumentNullException("transaction");
            if (transaction != null && transaction.Connection == null)
                throw new ArgumentException(
                    "The transaction was rollbacked or commited, please provide an open transaction.", "transaction");

            // Create a command and prepare it for execution
            // 创建一个准备执行的命令
            var cmd = new OracleCommand();
            bool mustCloseConnection = false;
            PrepareCommand(cmd, transaction.Connection, transaction, commandType, commandText, commandTimeout,
                           commandParameters, out mustCloseConnection);

            // Finally, execute the command
            // 最后，执行命令
            int retval = cmd.ExecuteNonQuery();

            // Detach the OracleParameters from the command object, so they can be used again
            // 从命令对象中分离sql参数，以便于它们可以被再次使用
            cmd.Parameters.Clear();
            return retval;
        }

        /// <summary>
        ///     通过一个返回1个结果集合的sql命令来执行一个提供了参数值的存储过程，针对指定的Sql事务。
        ///     这个方法为了发现存储过程(每一个存储过程第一次被调用)的参数，它将会查询数据库并且按照参数顺序给参数赋值。
        /// </summary>
        /// <param name="transaction">一个有效的sql事务</param>
        /// <param name="spName">存储过程的名字</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <param name="parameterValues">存储过程输入的值赋给这个对象数组</param>
        /// <returns>受命令影响的行数(整型)</returns>
        public static int ExecuteNonQuery(OracleTransaction transaction, string spName, int commandTimeout,
                                          params object[] parameterValues)
        {
            if (transaction == null) throw new ArgumentNullException("transaction");
            if (transaction != null && transaction.Connection == null)
                throw new ArgumentException(
                    "The transaction was rollbacked or commited, please provide an open transaction.", "transaction");
            if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");

            // If we receive parameter values, we need to figure out where they go
            // 如果我们接受到参数值，我们需要知道它们来自那里
            if ((parameterValues != null) && (parameterValues.Length > 0))
            {
                // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
                // 从存放着参数的缓存器中填充这个存储过程的参数

                OracleParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(transaction.Connection,
                                                                                                spName);

                // Assign the provided values to these parameters based on parameter order
                // 按参数顺序给这些参数赋值
                AssignParameterValues(commandParameters, parameterValues);

                // Call the overload that takes an array of OracleParameters
                // 调用接受Sql参数数组的overload

                return ExecuteNonQuery(transaction, CommandType.StoredProcedure, spName, commandTimeout,
                                       commandParameters);
            }
            else
            {
                // Otherwise we can just call the SP without params
                // 否则，我们只能调用没有参数的SP
                return ExecuteNonQuery(transaction, CommandType.StoredProcedure, spName, commandTimeout);
            }
        }

        #endregion ExecuteNonQuery

        #region ExecuteDataset

        /// <summary>
        ///     执行一个Sql命令(返回一个结果集合并且不返回参数),这个命令是依附于指定了连接字符串的数据库
        /// </summary>
        /// <param name="connectionString">一个有效的Sql连接字符串</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令</param>
        /// <returns>一个包含由命令产生结果集合的dataset</returns>
        public static DataSet ExecuteDataset(string connectionString, CommandType commandType, string commandText)
        {
            // Pass through the call providing null for the set of OracleParameters
            // 通过一个为Sql参数提供null值的调用
            return ExecuteDataset(connectionString, commandType, commandText, null);
        }

        /// <summary>
        ///     使用提供的参数执行一个Sql命令(返回一个结果集合),这个命令是依附于指定了连接字符串的数据库
        /// </summary>
        /// <param name="connectionString">一个有效的Sql连接字符串</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令</param>
        /// <param name="commandParameters">用于执行命令的Sql参数数组</param>
        /// <returns>包含由命令产生的结果集合的dataset</returns>
        public static DataSet ExecuteDataset(string connectionString, CommandType commandType, string commandText,
                                             params OracleParameter[] commandParameters)
        {
            if (connectionString == null || connectionString.Length == 0)
                throw new ArgumentNullException("connectionString");

            // Create & open a OracleConnection, and dispose of it after we are done
            // 创建和打开sql连接，不用时把它释放掉
            using (var connection = new OracleConnection(connectionString))
            {
                connection.Open();

                // Call the overload that takes a connection in place of the connection string
                // 调用这个在连接字符串中截取适当连接字符串的overload  

                return ExecuteDataset(connection, commandType, commandText, commandParameters);
            }
        }

        /// <summary>
        ///     通过一个返回结果集合的sql命令(返回一个结果集合)来执行一个提供了参数值的存储过程，针对指定的数据库。
        ///     这个方法为了发现存储过程(每一个存储过程第一次被调用)的参数，它将会查询数据库并且按照参数顺序给参数赋值。
        /// </summary>
        /// <param name="connectionString">一个有效的Sql连接字符串</param>
        /// <param name="spName">存储过程的名字</param>
        /// <param name="parameterValues">存储过程输入的值赋给这个对象数组</param>
        /// <returns>包含由命令产生的结果集合的dataset</returns>
        public static DataSet ExecuteDataset(string connectionString, string spName, params object[] parameterValues)
        {
            if (connectionString == null || connectionString.Length == 0)
                throw new ArgumentNullException("connectionString");
            if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");

            // If we receive parameter values, we need to figure out where they go
            // 如果我们接受到参数值，我们需要知道它们来自那里

            if ((parameterValues != null) && (parameterValues.Length > 0))
            {
                // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
                // 从存放着参数的缓存器中填充这个存储过程的参数
                OracleParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connectionString, spName);

                // Assign the provided values to these parameters based on parameter order
                // 按参数顺序给这些参数赋值
                AssignParameterValues(commandParameters, parameterValues);

                // Call the overload that takes an array of OracleParameters
                // 调用接受Sql参数数组的overload
                return ExecuteDataset(connectionString, CommandType.StoredProcedure, spName, commandParameters);
            }
            else
            {
                // Otherwise we can just call the SP without params
                // 否则，我们只能调用没有参数的SP
                return ExecuteDataset(connectionString, CommandType.StoredProcedure, spName);
            }
        }

        /// <summary>
        ///     执行一个Sql命令(返回一个结果集合并且不返回参数),这个命令是依附于提供的sql连接
        /// </summary>
        /// <param name="connection">一个有效的Sql连接</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令</param>
        /// <returns>包含由命令产生的结果集合的dataset</returns>
        public static DataSet ExecuteDataset(OracleConnection connection, CommandType commandType, string commandText)
        {
            // Pass through the call providing null for the set of OracleParameters
            // 通过一个为Sql参数提供null值的调用
            return ExecuteDataset(connection, commandType, commandText, null);
        }

        /// <summary>
        ///     使用提供的参数执行一个Sql命令(返回一个结果集合)，针对这个指定的Sql连接
        /// </summary>
        /// <param name="connection">一个有效的Sql连接</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)。</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令。</param>
        /// <param name="commandParameters">用于执行命令的Sql参数数组</param>
        /// <returns>包含由命令产生的结果集合的dataset</returns>
        public static DataSet ExecuteDataset(OracleConnection connection, CommandType commandType, string commandText,
                                             params OracleParameter[] commandParameters)
        {
            if (connection == null) throw new ArgumentNullException("connection");

            // Create a command and prepare it for execution
            // 创建一个命令并且准备执行它
            var cmd = new OracleCommand();
            bool mustCloseConnection = true;
            PrepareCommand(cmd, connection, null, commandType, commandText, commandParameters, out mustCloseConnection);

            // Create the DataAdapter & DataSet
            // 创建DataAdapter & DataSet

            //OracleDataAdapter
            using (var da = new OracleDataAdapter(cmd))
            {
                var ds = new DataSet();

                // Fill the DataSet using default values for DataTable names, etc
                // 使用数据表名的默认值来填充DataSet

                da.Fill(ds);

                // Detach the OracleParameters from the command object, so they can be used again
                // 从命令对象分离这个Sql参数，以便于它们可以再次被使用
                cmd.Parameters.Clear();

                if (mustCloseConnection)
                    connection.Close();

                // Return the dataset
                // 返回dataset
                return ds;
            }
        }

        /// <summary>
        ///     通过一个返回结果集合的sql命令(返回一个结果集合)来执行一个提供了参数值的存储过程，针对指定的Sql连接。
        ///     这个方法为了发现存储过程(每一个存储过程第一次被调用)的参数，它将会查询数据库并且按照参数顺序给参数赋值。
        /// </summary>
        /// <param name="connection">一个有效的Sql连接</param>
        /// <param name="spName">存储过程的名字</param>
        /// <param name="parameterValues">存储过程输入的值赋给这个对象数组</param>
        /// <returns>包含由命令产生的结果集合的dataset</returns>
        public static DataSet ExecuteDataset(OracleConnection connection, string spName, params object[] parameterValues)
        {
            if (connection == null) throw new ArgumentNullException("connection");
            if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");

            // If we receive parameter values, we need to figure out where they go
            // 如果我们接受到参数值，我们需要知道它们来自那里

            if ((parameterValues != null) && (parameterValues.Length > 0))
            {
                // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
                // 从存放着参数的缓存器中填充这个存储过程的参数
                OracleParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connection, spName);

                // Assign the provided values to these parameters based on parameter order
                // 按参数顺序给这些参数赋值
                AssignParameterValues(commandParameters, parameterValues);

                // Call the overload that takes an array of OracleParameters
                // 调用接受Sql参数数组的overload
                return ExecuteDataset(connection, CommandType.StoredProcedure, spName, commandParameters);
            }
            else
            {
                // Otherwise we can just call the SP without params
                // 否则，我们只能调用没有参数的SP
                return ExecuteDataset(connection, CommandType.StoredProcedure, spName);
            }
        }

        /// <summary>
        ///     执行一个Sql命令（返回一个结果集合并且不带参数)，针对这个提供的Sql事务
        /// </summary>
        /// <param name="transaction">一个有效的sql事务</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)。</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令。</param>
        /// <returns>包含由命令产生的结果集合的dataset</returns>
        public static DataSet ExecuteDataset(OracleTransaction transaction, CommandType commandType, string commandText)
        {
            // Pass through the call providing null for the set of OracleParameters
            // 通过一个为Sql参数提供null值的调用
            return ExecuteDataset(transaction, commandType, commandText, null);
        }

        /// <summary>
        ///     使用提供的参数执行一个Sql命令(返回一个结果集合)，针对这个指定的Sql事务
        /// </summary>
        /// <param name="transaction">一个有效的Sql事务</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令。</param>
        /// <param name="commandParameters">用于执行命令的Sql参数数组</param>
        /// <returns>包含由命令产生的结果集合的dataset</returns>
        public static DataSet ExecuteDataset(OracleTransaction transaction, CommandType commandType, string commandText,
                                             params OracleParameter[] commandParameters)
        {
            if (transaction == null) throw new ArgumentNullException("transaction");
            if (transaction != null && transaction.Connection == null)
                throw new ArgumentException(
                    "The transaction was rollbacked or commited, please provide an open transaction.", "transaction");

            // Create a command and prepare it for execution
            // 创建一个准备执行的命令
            var cmd = new OracleCommand();
            bool mustCloseConnection = false;
            PrepareCommand(cmd, transaction.Connection, transaction, commandType, commandText, commandParameters,
                           out mustCloseConnection);

            // Create the DataAdapter & DataSet
            // 创建DataAdapte和DataSet
            using (var da = new OracleDataAdapter(cmd))
            {
                var ds = new DataSet();

                // Fill the DataSet using default values for DataTable names, etc
                // 使用数据表名的默认值来填充DataSet
                da.Fill(ds);

                // Detach the OracleParameters from the command object, so they can be used again
                // 从命令对象分离这个Sql参数，以便于它们可以再次被使用
                cmd.Parameters.Clear();

                // Return the dataset
                // 返回dataset
                return ds;
            }
        }

        /// <summary>
        ///     通过一个返回结果集合的sql命令(返回一个结果集合)来执行一个提供了参数值的存储过程，针对指定的Sql事务。
        ///     这个方法为了发现存储过程(每一个存储过程第一次被调用)的参数，它将会查询数据库并且按照参数顺序给参数赋值。
        /// </summary>
        /// <param name="transaction">一个有效的事务</param>
        /// <param name="spName">存储过程的名字</param>
        /// <param name="parameterValues">存储过程输入的值赋给这个对象数组</param>
        /// <returns>包含由命令产生结果集合的dataset</returns>
        public static DataSet ExecuteDataset(OracleTransaction transaction, string spName,
                                             params object[] parameterValues)
        {
            if (transaction == null) throw new ArgumentNullException("transaction");
            if (transaction != null && transaction.Connection == null)
                throw new ArgumentException(
                    "The transaction was rollbacked or commited, please provide an open transaction.", "transaction");
            if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");

            // If we receive parameter values, we need to figure out where they go
            // 如果我们接受到参数值，我们需要知道它们来自那里
            if ((parameterValues != null) && (parameterValues.Length > 0))
            {
                // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
                // 从存放着参数的缓存器中填充这个存储过程的参数
                OracleParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(transaction.Connection,
                                                                                                spName);

                // Assign the provided values to these parameters based on parameter order
                // 按参数顺序给这些参数赋值

                AssignParameterValues(commandParameters, parameterValues);

                // Call the overload that takes an array of OracleParameters
                // 调用接受Sql参数数组的overload
                return ExecuteDataset(transaction, CommandType.StoredProcedure, spName, commandParameters);
            }
            else
            {
                // Otherwise we can just call the SP without params
                // 否则，我们只能调用没有参数的SP

                return ExecuteDataset(transaction, CommandType.StoredProcedure, spName);
            }
        }

        /// <summary>
        ///     执行一个Sql命令(返回一个结果集合并且不返回参数),这个命令是依附于指定了连接字符串的数据库
        /// </summary>
        /// <param name="connectionString">一个有效的Sql连接字符串</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <returns>一个包含由命令产生结果集合的dataset</returns>
        public static DataSet ExecuteDataset(string connectionString, CommandType commandType, string commandText,
                                             int commandTimeout)
        {
            // Pass through the call providing null for the set of OracleParameters
            // 通过一个为Sql参数提供null值的调用
            return ExecuteDataset(connectionString, commandType, commandText, commandTimeout, null);
        }

        /// <summary>
        ///     使用提供的参数执行一个Sql命令(返回一个结果集合),这个命令是依附于指定了连接字符串的数据库
        /// </summary>
        /// <param name="connectionString">一个有效的Sql连接字符串</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <param name="commandParameters">用于执行命令的Sql参数数组</param>
        /// <returns>包含由命令产生的结果集合的dataset</returns>
        public static DataSet ExecuteDataset(string connectionString, CommandType commandType, string commandText,
                                             int commandTimeout, params OracleParameter[] commandParameters)
        {
            if (connectionString == null || connectionString.Length == 0)
                throw new ArgumentNullException("connectionString");

            // Create & open a OracleConnection, and dispose of it after we are done
            // 创建和打开sql连接，不用时把它释放掉
            using (var connection = new OracleConnection(connectionString))
            {
                connection.Open();

                // Call the overload that takes a connection in place of the connection string
                // 调用这个在连接字符串中截取适当连接字符串的overload  

                return ExecuteDataset(connection, commandType, commandText, commandTimeout, commandParameters);
            }
        }

        /// <summary>
        ///     通过一个返回结果集合的sql命令(返回一个结果集合)来执行一个提供了参数值的存储过程，针对指定的数据库。
        ///     这个方法为了发现存储过程(每一个存储过程第一次被调用)的参数，它将会查询数据库并且按照参数顺序给参数赋值。
        /// </summary>
        /// <param name="connectionString">一个有效的Sql连接字符串</param>
        /// <param name="spName">存储过程的名字</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <param name="parameterValues">存储过程输入的值赋给这个对象数组</param>
        /// <returns>包含由命令产生的结果集合的dataset</returns>
        public static DataSet ExecuteDataset(string connectionString, string spName, int commandTimeout,
                                             params object[] parameterValues)
        {
            if (connectionString == null || connectionString.Length == 0)
                throw new ArgumentNullException("connectionString");
            if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");

            // If we receive parameter values, we need to figure out where they go
            // 如果我们接受到参数值，我们需要知道它们来自那里

            if ((parameterValues != null) && (parameterValues.Length > 0))
            {
                // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
                // 从存放着参数的缓存器中填充这个存储过程的参数
                OracleParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connectionString, spName);

                // Assign the provided values to these parameters based on parameter order
                // 按参数顺序给这些参数赋值
                AssignParameterValues(commandParameters, parameterValues);

                // Call the overload that takes an array of OracleParameters
                // 调用接受Sql参数数组的overload
                return ExecuteDataset(connectionString, CommandType.StoredProcedure, spName, commandTimeout,
                                      commandParameters);
            }
            else
            {
                // Otherwise we can just call the SP without params
                // 否则，我们只能调用没有参数的SP
                return ExecuteDataset(connectionString, CommandType.StoredProcedure, spName, commandTimeout);
            }
        }

        /// <summary>
        ///     执行一个Sql命令(返回一个结果集合并且不返回参数),这个命令是依附于提供的sql连接
        /// </summary>
        /// <param name="connection">一个有效的Sql连接</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <returns>包含由命令产生的结果集合的dataset</returns>
        public static DataSet ExecuteDataset(OracleConnection connection, CommandType commandType, string commandText,
                                             int commandTimeout)
        {
            // Pass through the call providing null for the set of OracleParameters
            // 通过一个为Sql参数提供null值的调用
            return ExecuteDataset(connection, commandType, commandText, commandTimeout, null);
        }

        /// <summary>
        ///     使用提供的参数执行一个Sql命令(返回一个结果集合)，针对这个指定的Sql连接
        /// </summary>
        /// <param name="connection">一个有效的Sql连接</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)。</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令。</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <param name="commandParameters">用于执行命令的Sql参数数组</param>
        /// <returns>包含由命令产生的结果集合的dataset</returns>
        public static DataSet ExecuteDataset(OracleConnection connection, CommandType commandType, string commandText,
                                             int commandTimeout, params OracleParameter[] commandParameters)
        {
            if (connection == null) throw new ArgumentNullException("connection");

            // Create a command and prepare it for execution
            // 创建一个命令并且准备执行它
            var cmd = new OracleCommand();
            bool mustCloseConnection = false;
            PrepareCommand(cmd, connection, null, commandType, commandText, commandTimeout, commandParameters,
                           out mustCloseConnection);

            // Create the DataAdapter & DataSet
            // 创建DataAdapter & DataSet
            using (var da = new OracleDataAdapter(cmd))
            {
                var ds = new DataSet();

                // Fill the DataSet using default values for DataTable names, etc
                // 使用数据表名的默认值来填充DataSet

                da.Fill(ds);

                // Detach the OracleParameters from the command object, so they can be used again
                // 从命令对象分离这个Sql参数，以便于它们可以再次被使用
                cmd.Parameters.Clear();

                if (mustCloseConnection)
                    connection.Close();

                // Return the dataset
                // 返回dataset
                return ds;
            }
        }

        /// <summary>
        ///     通过一个返回结果集合的sql命令(返回一个结果集合)来执行一个提供了参数值的存储过程，针对指定的Sql连接。
        ///     这个方法为了发现存储过程(每一个存储过程第一次被调用)的参数，它将会查询数据库并且按照参数顺序给参数赋值。
        /// </summary>
        /// <param name="connection">一个有效的Sql连接</param>
        /// <param name="spName">存储过程的名字</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <param name="parameterValues">存储过程输入的值赋给这个对象数组</param>
        /// <returns>包含由命令产生的结果集合的dataset</returns>
        public static DataSet ExecuteDataset(OracleConnection connection, string spName, int commandTimeout,
                                             params object[] parameterValues)
        {
            if (connection == null) throw new ArgumentNullException("connection");
            if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");

            // If we receive parameter values, we need to figure out where they go
            // 如果我们接受到参数值，我们需要知道它们来自那里

            if ((parameterValues != null) && (parameterValues.Length > 0))
            {
                // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
                // 从存放着参数的缓存器中填充这个存储过程的参数
                OracleParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connection, spName);

                // Assign the provided values to these parameters based on parameter order
                // 按参数顺序给这些参数赋值
                AssignParameterValues(commandParameters, parameterValues);

                // Call the overload that takes an array of OracleParameters
                // 调用接受Sql参数数组的overload
                return ExecuteDataset(connection, CommandType.StoredProcedure, spName, commandTimeout, commandParameters);
            }
            else
            {
                // Otherwise we can just call the SP without params
                // 否则，我们只能调用没有参数的SP
                return ExecuteDataset(connection, CommandType.StoredProcedure, spName, commandTimeout);
            }
        }

        /// <summary>
        ///     执行一个Sql命令（返回一个结果集合并且不带参数)，针对这个提供的Sql事务
        /// </summary>
        /// <param name="transaction">一个有效的sql事务</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)。</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令。</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <returns>包含由命令产生的结果集合的dataset</returns>
        public static DataSet ExecuteDataset(OracleTransaction transaction, CommandType commandType, string commandText,
                                             int commandTimeout)
        {
            // Pass through the call providing null for the set of OracleParameters
            // 通过一个为Sql参数提供null值的调用
            return ExecuteDataset(transaction, commandType, commandText, commandTimeout, null);
        }

        /// <summary>
        ///     使用提供的参数执行一个Sql命令(返回一个结果集合)，针对这个指定的Sql事务
        /// </summary>
        /// <param name="transaction">一个有效的Sql事务</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令。</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <param name="commandParameters">用于执行命令的Sql参数数组</param>
        /// <returns>包含由命令产生的结果集合的dataset</returns>
        public static DataSet ExecuteDataset(OracleTransaction transaction, CommandType commandType, string commandText,
                                             int commandTimeout, params OracleParameter[] commandParameters)
        {
            if (transaction == null) throw new ArgumentNullException("transaction");
            if (transaction != null && transaction.Connection == null)
                throw new ArgumentException(
                    "The transaction was rollbacked or commited, please provide an open transaction.", "transaction");

            // Create a command and prepare it for execution
            // 创建一个准备执行的命令
            var cmd = new OracleCommand();
            bool mustCloseConnection = false;
            PrepareCommand(cmd, transaction.Connection, transaction, commandType, commandText, commandTimeout,
                           commandParameters, out mustCloseConnection);

            // Create the DataAdapter & DataSet
            // 创建DataAdapte和DataSet
            using (var da = new OracleDataAdapter(cmd))
            {
                var ds = new DataSet();

                // Fill the DataSet using default values for DataTable names, etc
                // 使用数据表名的默认值来填充DataSet
                da.Fill(ds);

                // Detach the OracleParameters from the command object, so they can be used again
                // 从命令对象分离这个Sql参数，以便于它们可以再次被使用
                cmd.Parameters.Clear();

                // Return the dataset
                // 返回dataset
                return ds;
            }
        }

        /// <summary>
        ///     通过一个返回结果集合的sql命令(返回一个结果集合)来执行一个提供了参数值的存储过程，针对指定的Sql事务。
        ///     这个方法为了发现存储过程(每一个存储过程第一次被调用)的参数，它将会查询数据库并且按照参数顺序给参数赋值。
        /// </summary>
        /// <param name="transaction">一个有效的事务</param>
        /// <param name="spName">存储过程的名字</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <param name="parameterValues">存储过程输入的值赋给这个对象数组</param>
        /// <returns>包含由命令产生结果集合的dataset</returns>
        public static DataSet ExecuteDataset(OracleTransaction transaction, string spName, int commandTimeout,
                                             params object[] parameterValues)
        {
            if (transaction == null) throw new ArgumentNullException("transaction");
            if (transaction != null && transaction.Connection == null)
                throw new ArgumentException(
                    "The transaction was rollbacked or commited, please provide an open transaction.", "transaction");
            if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");

            // If we receive parameter values, we need to figure out where they go
            // 如果我们接受到参数值，我们需要知道它们来自那里
            if ((parameterValues != null) && (parameterValues.Length > 0))
            {
                // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
                // 从存放着参数的缓存器中填充这个存储过程的参数
                OracleParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(transaction.Connection,
                                                                                                spName);

                // Assign the provided values to these parameters based on parameter order
                // 按参数顺序给这些参数赋值

                AssignParameterValues(commandParameters, parameterValues);

                // Call the overload that takes an array of OracleParameters
                // 调用接受Sql参数数组的overload
                return ExecuteDataset(transaction, CommandType.StoredProcedure, spName, commandTimeout,
                                      commandParameters);
            }
            else
            {
                // Otherwise we can just call the SP without params
                // 否则，我们只能调用没有参数的SP

                return ExecuteDataset(transaction, CommandType.StoredProcedure, spName, commandTimeout);
            }
        }

        #endregion ExecuteDataset

        #region ExecuteReader

        //OracleDataReader
        /// <summary>
        ///     创建和准备一个Sql命令，用适当的命令行为来调用这个ExecuteReader
        /// </summary>
        /// <remarks>
        ///     如果我们创建并且打开了这个连接，当DataReader被关闭时，我们想让这个连接关闭
        ///     如果调用者提供这个连接，我们想要断开它们，以便于管理
        /// </remarks>
        /// <param name="connection">在这个有效的sql连接上执行这个命令</param>
        /// <param name="transaction">一个有效的sql事务，或者'null'值</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令</param>
        /// <param name="commandParameters">和这个命令有联系的sql参数数组 或者 如果不用参数，那它就为null值</param>
        /// <param name="connectionOwnership">指出这个连接的参数是否被调用者提供, 或者通过SqlHelper来提供</param>
        /// <returns>OracleDataReader包含命令结果的OracleDataReader</returns>
        private static OracleDataReader ExecuteReader(OracleConnection connection, OracleTransaction transaction,
                                                      CommandType commandType, string commandText,
                                                      OracleParameter[] commandParameters,
                                                      OracleConnectionOwnership connectionOwnership)
        {
            if (connection == null) throw new ArgumentNullException("connection");

            bool mustCloseConnection = false;
            // Create a command and prepare it for execution
            //  创建一个用来执行的命令
            var cmd = new OracleCommand();
            try
            {
                PrepareCommand(cmd, connection, transaction, commandType, commandText, commandParameters,
                               out mustCloseConnection);

                // Create a reader
                //  创建一个reader
                OracleDataReader dataReader;

                // Call ExecuteReader with the appropriate CommandBehavior
                // 用适当的命令来调用ExecuteReader
                if (connectionOwnership == OracleConnectionOwnership.External)
                {
                    dataReader = cmd.ExecuteReader();
                }
                else
                {
                    dataReader = cmd.ExecuteReader(CommandBehavior.CloseConnection);
                }

                // Detach the OracleParameters from the command object, so they can be used again.
                // HACK: There is a problem here, the output parameter values are fletched 
                // when the reader is closed, so if the parameters are detached from the command
                // then the SqlReader can set its values. 
                // When this happen, the parameters can be used again in other command.
                // 从命令对象分离Sql参数，以便于它们能再次被使用
                // 这儿有一个问题，输出参数的值被匹配
                // 如果参数从命令中分离出来，这个reader就被关闭
                // 那么，SqlReader就能够设置它的值
                // 这一切发生了，参数可以在别的命令中被使用
                bool canClear = true;
                foreach (OracleParameter commandParameter in cmd.Parameters)
                {
                    if (commandParameter.Direction != ParameterDirection.Input)
                        canClear = false;
                }

                if (canClear)
                {
                    cmd.Parameters.Clear();
                }

                return dataReader;
            }
            catch
            {
                if (mustCloseConnection)
                    connection.Close();
                throw;
            }
        }

        /// <summary>
        ///     使用提供的参数执行一个Sql命令(返回一个结果集合)，针对这个指定了连接字符串的数据库
        /// </summary>
        /// <param name="connectionString">一个有效的Sql连接字符串</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令</param>
        /// <returns>包含由命令产生结果集合的一个OracleDataReader</returns>
        public static OracleDataReader ExecuteReader(string connectionString, CommandType commandType,
                                                     string commandText)
        {
            // Pass through the call providing null for the set of OracleParameters
            // 通过一个为sql参数提供null值的调用 
            return ExecuteReader(connectionString, commandType, commandText, null);
        }

        /// <summary>
        ///     执行一个Sql命令(返回一个结果集合)，针对这个指定了连接字符串的数据库
        /// </summary>
        /// <param name="connectionString">一个有效的Sql连接字符串</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令</param>
        /// <param name="commandParameters">用于执行命令的Sql参数数组</param>
        /// <returns>包含由命令产生结果集合的一个OracleDataReader</returns>
        public static OracleDataReader ExecuteReader(string connectionString, CommandType commandType,
                                                     string commandText, params OracleParameter[] commandParameters)
        {
            if (connectionString == null || connectionString.Length == 0)
                throw new ArgumentNullException("connectionString");
            OracleConnection connection = null;
            try
            {
                connection = new OracleConnection(connectionString);
                connection.Open();

                // Call the private overload that takes an internally owned connection in place of the connection string
                // 调用这个在连接字符串中截取适当连接字符串的overload  
                return ExecuteReader(connection, null, commandType, commandText, commandParameters,
                                     OracleConnectionOwnership.Internal);
            }
            catch
            {
                // If we fail to return the SqlDatReader, we need to close the connection ourselves
                // 如果我们返回OracleDataReader失败，我们要关闭这个连接

                if (connection != null) connection.Close();
                throw;
            }
        }

        /// <summary>
        ///     通过一个返回结果集合的sql命令(返回一个结果集合)来执行一个提供了参数值的存储过程，针对指定的连接字符串。
        ///     这个方法为了发现存储过程(每一个存储过程第一次被调用)的参数，它将会查询数据库并且按照参数顺序给参数赋值。
        /// </summary>
        /// <param name="connectionString">一个有效的Sql连接字符串</param>
        /// <param name="spName">存储过程的名字</param>
        /// <param name="parameterValues">存储过程输入的值赋给这个对象数组</param>
        /// <returns>包含由命令产生结果集合的一个OracleDataReader</returns>
        public static OracleDataReader ExecuteReader(string connectionString, string spName,
                                                     params object[] parameterValues)
        {
            if (connectionString == null || connectionString.Length == 0)
                throw new ArgumentNullException("connectionString");
            if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");

            // If we receive parameter values, we need to figure out where they go
            // 如果我们接受到参数值，我们需要知道它们来自那里
            if ((parameterValues != null) && (parameterValues.Length > 0))
            {
                OracleParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connectionString, spName);

                AssignParameterValues(commandParameters, parameterValues);

                return ExecuteReader(connectionString, CommandType.StoredProcedure, spName, commandParameters);
            }
            else
            {
                // Otherwise we can just call the SP without params
                // 否则 我们仅仅只能调用没有参数的SP
                return ExecuteReader(connectionString, CommandType.StoredProcedure, spName);
            }
        }

        /// <summary>
        ///     执行一个Sql命令（返回一个结果集合并且不带参数)，针对这个提供的Sql连接
        /// </summary>
        /// <param name="connection">一个有效的Sql连接</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令</param>
        /// <returns>包含由命令产生结果集合的一个OracleDataReader</returns>
        public static OracleDataReader ExecuteReader(OracleConnection connection, CommandType commandType,
                                                     string commandText)
        {
            // Pass through the call providing null for the set of OracleParameters
            // 通过一个为Sql参数提供null值的调用
            return ExecuteReader(connection, commandType, commandText, null);
        }

        /// <summary>
        ///     执行一个Sql命令(返回一个结果集合)，针对这个指定的Sql连接
        /// </summary>
        /// <param name="connection">一个有效的Sql连接</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令。</param>
        /// <param name="commandParameters">用于执行命令的Sql参数数组</param>
        /// <returns>包含由命令产生结果集合的一个OracleDataReader</returns>
        public static OracleDataReader ExecuteReader(OracleConnection connection, CommandType commandType,
                                                     string commandText, params OracleParameter[] commandParameters)
        {
            // Pass through the call to the private overload using a null transaction value and an externally owned connection
            // 通过一个使用null值的事务和一个你所拥有的连接来调用private overload
            return ExecuteReader(connection, null, commandType, commandText, commandParameters,
                                 OracleConnectionOwnership.External);
        }

        /// <summary>
        ///     通过一个返回结果集合的sql命令来执行一个提供了参数值的存储过程，针对指定的Sql连接。
        ///     这个方法为了发现存储过程(每一个存储过程第一次被调用)的参数，它将会查询数据库并且按照参数顺序给参数赋值。
        /// </summary>
        /// <param name="connection">一个有效的Sql连接</param>
        /// <param name="spName">存储过程的名字</param>
        /// <param name="parameterValues">存储过程输入的值赋给这个对象数组</param>
        /// <returns>包含由命令产生结果集合的一个OracleDataReader</returns>
        public static OracleDataReader ExecuteReader(OracleConnection connection, string spName,
                                                     params object[] parameterValues)
        {
            if (connection == null) throw new ArgumentNullException("connection");
            if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");

            // If we receive parameter values, we need to figure out where they go
            // 如果我们接受到参数值，我们需要知道它们来自那里


            if ((parameterValues != null) && (parameterValues.Length > 0))
            {
                OracleParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connection, spName);

                AssignParameterValues(commandParameters, parameterValues);

                return ExecuteReader(connection, CommandType.StoredProcedure, spName, commandParameters);
            }
            else
            {
                // Otherwise we can just call the SP without params
                // 否则 我们仅仅只能调用没有参数的SP

                return ExecuteReader(connection, CommandType.StoredProcedure, spName);
            }
        }

        /// <summary>
        ///     执行一个Sql命令（返回一个结果集合并且不带参数)，针对这个提供的Sql事务
        /// </summary>
        /// <param name="transaction">一个有效的Sql事务</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令。</param>
        /// <returns>包含由命令产生结果集合的一个OracleDataReader</returns>
        public static OracleDataReader ExecuteReader(OracleTransaction transaction, CommandType commandType,
                                                     string commandText)
        {
            // Pass through the call providing null for the set of OracleParameters
            // 通过一个为Sql参数提供null值的调用
            return ExecuteReader(transaction, commandType, commandText, null);
        }

        /// <summary>
        ///     使用提供的参数执行一个Sql命令(返回一个结果集合)，针对这个指定的Sql事务
        /// </summary>
        /// <param name="transaction">一个有效的Sql事务</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令。</param>
        /// <param name="commandParameters">用于执行命令的Sql参数数组</param>
        /// <returns>包含由命令产生结果集合的一个OracleDataReader</returns>
        public static OracleDataReader ExecuteReader(OracleTransaction transaction, CommandType commandType,
                                                     string commandText, params OracleParameter[] commandParameters)
        {
            if (transaction == null) throw new ArgumentNullException("transaction");
            if (transaction != null && transaction.Connection == null)
                throw new ArgumentException(
                    "The transaction was rollbacked or commited, please provide an open transaction.", "transaction");

            // Pass through to private overload, indicating that the connection is owned by the caller
            // 通过这个private overload，显示调用者拥有的连接
            return ExecuteReader(transaction.Connection, transaction, commandType, commandText, commandParameters,
                                 OracleConnectionOwnership.External);
        }

        /// <summary>
        ///     通过Sql命令(返回一个结果集合)来执行这个存储过程，
        ///     这个存储过程是为指定一个使用提供参数值的Sql事务服务的。
        ///     这个方法为了发现存储过程(每一个第一次被调用的存储过程)的参数，它将会查询数据库, 并且按照参数的顺序给参数赋值。
        /// </summary>
        /// <param name="transaction">一个有效的Sql事务</param>
        /// <param name="spName">存储过程的名字</param>
        /// <param name="parameterValues">存储过程输入的值赋给这个对象数组</param>
        /// <returns>包含由命令产生结果集合的一个OracleDataReader</returns>
        public static OracleDataReader ExecuteReader(OracleTransaction transaction, string spName,
                                                     params object[] parameterValues)
        {
            if (transaction == null) throw new ArgumentNullException("transaction");
            if (transaction != null && transaction.Connection == null)
                throw new ArgumentException(
                    "The transaction was rollbacked or commited, please provide an open transaction.", "transaction");
            if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");

            // If we receive parameter values, we need to figure out where they go
            // 如果我们接受到参数值，我们需要知道它们来自那里
            if ((parameterValues != null) && (parameterValues.Length > 0))
            {
                OracleParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(transaction.Connection,
                                                                                                spName);

                AssignParameterValues(commandParameters, parameterValues);

                return ExecuteReader(transaction, CommandType.StoredProcedure, spName, commandParameters);
            }
            else
            {
                // Otherwise we can just call the SP without params
                // 否则 我们仅仅只能调用没有参数的SP

                return ExecuteReader(transaction, CommandType.StoredProcedure, spName);
            }
        }


        /// <summary>
        ///     创建和准备一个Sql命令，用适当的命令行为来调用这个ExecuteReader
        /// </summary>
        /// <remarks>
        ///     如果我们创建并且打开了这个连接，当DataReader被关闭时，我们想让这个连接关闭
        ///     如果调用者提供这个连接，我们想要断开它们，以便于管理
        /// </remarks>
        /// <param name="connection">在这个有效的sql连接上执行这个命令</param>
        /// <param name="transaction">一个有效的sql事务，或者'null'值</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <param name="commandParameters">和这个命令有联系的sql参数数组 或者 如果不用参数，那它就为null值</param>
        /// <param name="connectionOwnership">指出这个连接的参数是否被调用者提供, 或者通过SqlHelper来提供</param>
        /// <returns>OracleDataReader包含命令结果的OracleDataReader</returns>
        private static OracleDataReader ExecuteReader(OracleConnection connection, OracleTransaction transaction,
                                                      CommandType commandType, string commandText, int commandTimeout,
                                                      OracleParameter[] commandParameters,
                                                      OracleConnectionOwnership connectionOwnership)
        {
            if (connection == null) throw new ArgumentNullException("connection");

            bool mustCloseConnection = false;
            // Create a command and prepare it for execution
            //  创建一个用来执行的命令
            var cmd = new OracleCommand();
            try
            {
                PrepareCommand(cmd, connection, transaction, commandType, commandText, commandTimeout, commandParameters,
                               out mustCloseConnection);

                // Create a reader
                //  创建一个reader
                OracleDataReader dataReader;

                // Call ExecuteReader with the appropriate CommandBehavior
                // 用适当的命令来调用ExecuteReader
                if (connectionOwnership == OracleConnectionOwnership.External)
                {
                    dataReader = cmd.ExecuteReader();
                }
                else
                {
                    dataReader = cmd.ExecuteReader(CommandBehavior.CloseConnection);
                }

                // Detach the OracleParameters from the command object, so they can be used again.
                // HACK: There is a problem here, the output parameter values are fletched 
                // when the reader is closed, so if the parameters are detached from the command
                // then the SqlReader can set its values. 
                // When this happen, the parameters can be used again in other command.
                // 从命令对象分离Sql参数，以便于它们能再次被使用
                // 这儿有一个问题，输出参数的值被匹配
                // 如果参数从命令中分离出来，这个reader就被关闭
                // 那么，SqlReader就能够设置它的值
                // 这一切发生了，参数可以在别的命令中被使用
                bool canClear = true;
                foreach (OracleParameter commandParameter in cmd.Parameters)
                {
                    if (commandParameter.Direction != ParameterDirection.Input)
                        canClear = false;
                }

                if (canClear)
                {
                    cmd.Parameters.Clear();
                }

                return dataReader;
            }
            catch
            {
                if (mustCloseConnection)
                    connection.Close();
                throw;
            }
        }


        /// <summary>
        ///     使用提供的参数执行一个Sql命令(返回一个结果集合)，针对这个指定了连接字符串的数据库
        /// </summary>
        /// <param name="connectionString">一个有效的Sql连接字符串</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <returns>包含由命令产生结果集合的一个OracleDataReader</returns>
        public static OracleDataReader ExecuteReader(string connectionString, CommandType commandType,
                                                     string commandText, int commandTimeout)
        {
            // Pass through the call providing null for the set of OracleParameters
            // 通过一个为sql参数提供null值的调用 
            return ExecuteReader(connectionString, commandType, commandText, commandTimeout, null);
        }


        /// <summary>
        ///     执行一个Sql命令(返回一个结果集合)，针对这个指定了连接字符串的数据库
        /// </summary>
        /// <param name="connectionString">一个有效的Sql连接字符串</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <param name="commandParameters">用于执行命令的Sql参数数组</param>
        /// <returns>包含由命令产生结果集合的一个OracleDataReader</returns>
        public static OracleDataReader ExecuteReader(string connectionString, CommandType commandType,
                                                     string commandText, int commandTimeout,
                                                     params OracleParameter[] commandParameters)
        {
            if (connectionString == null || connectionString.Length == 0)
                throw new ArgumentNullException("connectionString");
            OracleConnection connection = null;
            try
            {
                connection = new OracleConnection(connectionString);
                connection.Open();

                // Call the private overload that takes an internally owned connection in place of the connection string
                // 调用这个在连接字符串中截取适当连接字符串的overload  
                return ExecuteReader(connection, null, commandType, commandText, commandTimeout, commandParameters,
                                     OracleConnectionOwnership.Internal);
            }
            catch
            {
                // If we fail to return the SqlDatReader, we need to close the connection ourselves
                // 如果我们返回OracleDataReader失败，我们要关闭这个连接

                if (connection != null) connection.Close();
                throw;
            }
        }


        /// <summary>
        ///     通过一个返回结果集合的sql命令(返回一个结果集合)来执行一个提供了参数值的存储过程，针对指定的连接字符串。
        ///     这个方法为了发现存储过程(每一个存储过程第一次被调用)的参数，它将会查询数据库并且按照参数顺序给参数赋值。
        /// </summary>
        /// <param name="connectionString">一个有效的Sql连接字符串</param>
        /// <param name="spName">存储过程的名字</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <param name="parameterValues">存储过程输入的值赋给这个对象数组</param>
        /// <returns>包含由命令产生结果集合的一个OracleDataReader</returns>
        public static OracleDataReader ExecuteReader(string connectionString, string spName, int commandTimeout,
                                                     params object[] parameterValues)
        {
            if (connectionString == null || connectionString.Length == 0)
                throw new ArgumentNullException("connectionString");
            if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");

            // If we receive parameter values, we need to figure out where they go
            // 如果我们接受到参数值，我们需要知道它们来自那里
            if ((parameterValues != null) && (parameterValues.Length > 0))
            {
                OracleParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connectionString, spName);

                AssignParameterValues(commandParameters, parameterValues);

                return ExecuteReader(connectionString, CommandType.StoredProcedure, spName, commandTimeout,
                                     commandParameters);
            }
            else
            {
                // Otherwise we can just call the SP without params
                // 否则 我们仅仅只能调用没有参数的SP
                return ExecuteReader(connectionString, CommandType.StoredProcedure, spName, commandTimeout);
            }
        }


        /// <summary>
        ///     执行一个Sql命令（返回一个结果集合并且不带参数)，针对这个提供的Sql连接
        /// </summary>
        /// <param name="connection">一个有效的Sql连接</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <returns>包含由命令产生结果集合的一个OracleDataReader</returns>
        public static OracleDataReader ExecuteReader(OracleConnection connection, CommandType commandType,
                                                     string commandText, int commandTimeout)
        {
            // Pass through the call providing null for the set of OracleParameters
            // 通过一个为Sql参数提供null值的调用
            return ExecuteReader(connection, commandType, commandText, commandTimeout, null);
        }


        /// <summary>
        ///     执行一个Sql命令(返回一个结果集合)，针对这个指定的Sql连接
        /// </summary>
        /// <param name="connection">一个有效的Sql连接</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令。</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <param name="commandParameters">用于执行命令的Sql参数数组</param>
        /// <returns>包含由命令产生结果集合的一个OracleDataReader</returns>
        public static OracleDataReader ExecuteReader(OracleConnection connection, CommandType commandType,
                                                     string commandText, int commandTimeout,
                                                     params OracleParameter[] commandParameters)
        {
            // Pass through the call to the private overload using a null transaction value and an externally owned connection
            // 通过一个使用null值的事务和一个你所拥有的连接来调用private overload
            return ExecuteReader(connection, null, commandType, commandText, commandTimeout, commandParameters,
                                 OracleConnectionOwnership.External);
        }


        /// <summary>
        ///     通过一个返回结果集合的sql命令来执行一个提供了参数值的存储过程，针对指定的Sql连接。
        ///     这个方法为了发现存储过程(每一个存储过程第一次被调用)的参数，它将会查询数据库并且按照参数顺序给参数赋值。
        /// </summary>
        /// <param name="connection">一个有效的Sql连接</param>
        /// <param name="spName">存储过程的名字</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <param name="parameterValues">存储过程输入的值赋给这个对象数组</param>
        /// <returns>包含由命令产生结果集合的一个OracleDataReader</returns>
        public static OracleDataReader ExecuteReader(OracleConnection connection, string spName, int commandTimeout,
                                                     params object[] parameterValues)
        {
            if (connection == null) throw new ArgumentNullException("connection");
            if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");

            // If we receive parameter values, we need to figure out where they go
            // 如果我们接受到参数值，我们需要知道它们来自那里


            if ((parameterValues != null) && (parameterValues.Length > 0))
            {
                OracleParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connection, spName);

                AssignParameterValues(commandParameters, parameterValues);

                return ExecuteReader(connection, CommandType.StoredProcedure, spName, commandTimeout, commandParameters);
            }
            else
            {
                // Otherwise we can just call the SP without params
                // 否则 我们仅仅只能调用没有参数的SP

                return ExecuteReader(connection, CommandType.StoredProcedure, spName, commandTimeout);
            }
        }


        /// <summary>
        ///     执行一个Sql命令（返回一个结果集合并且不带参数)，针对这个提供的Sql事务
        /// </summary>
        /// <param name="transaction">一个有效的Sql事务</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令。</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <returns>包含由命令产生结果集合的一个OracleDataReader</returns>
        public static OracleDataReader ExecuteReader(OracleTransaction transaction, CommandType commandType,
                                                     string commandText, int commandTimeout)
        {
            // Pass through the call providing null for the set of OracleParameters
            // 通过一个为Sql参数提供null值的调用
            return ExecuteReader(transaction, commandType, commandText, commandTimeout, null);
        }


        /// <summary>
        ///     使用提供的参数执行一个Sql命令(返回一个结果集合)，针对这个指定的Sql事务
        /// </summary>
        /// <param name="transaction">一个有效的Sql事务</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令。</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <param name="commandParameters">用于执行命令的Sql参数数组</param>
        /// <returns>包含由命令产生结果集合的一个OracleDataReader</returns>
        public static OracleDataReader ExecuteReader(OracleTransaction transaction, CommandType commandType,
                                                     string commandText, int commandTimeout,
                                                     params OracleParameter[] commandParameters)
        {
            if (transaction == null) throw new ArgumentNullException("transaction");
            if (transaction != null && transaction.Connection == null)
                throw new ArgumentException(
                    "The transaction was rollbacked or commited, please provide an open transaction.", "transaction");

            // Pass through to private overload, indicating that the connection is owned by the caller
            // 通过这个private overload，显示调用者拥有的连接
            return ExecuteReader(transaction.Connection, transaction, commandType, commandText, commandTimeout,
                                 commandParameters, OracleConnectionOwnership.External);
        }


        /// <summary>
        ///     通过Sql命令(返回一个结果集合)来执行这个存储过程，
        ///     这个存储过程是为指定一个使用提供参数值的Sql事务服务的。
        ///     这个方法为了发现存储过程(每一个第一次被调用的存储过程)的参数，它将会查询数据库, 并且按照参数的顺序给参数赋值。
        /// </summary>
        /// <param name="transaction">一个有效的Sql事务</param>
        /// <param name="spName">存储过程的名字</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <param name="parameterValues">存储过程输入的值赋给这个对象数组</param>
        /// <returns>包含由命令产生结果集合的一个OracleDataReader</returns>
        public static OracleDataReader ExecuteReader(OracleTransaction transaction, string spName, int commandTimeout,
                                                     params object[] parameterValues)
        {
            if (transaction == null) throw new ArgumentNullException("transaction");
            if (transaction != null && transaction.Connection == null)
                throw new ArgumentException(
                    "The transaction was rollbacked or commited, please provide an open transaction.", "transaction");
            if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");

            // If we receive parameter values, we need to figure out where they go
            // 如果我们接受到参数值，我们需要知道它们来自那里
            if ((parameterValues != null) && (parameterValues.Length > 0))
            {
                OracleParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(transaction.Connection,
                                                                                                spName);

                AssignParameterValues(commandParameters, parameterValues);

                return ExecuteReader(transaction, CommandType.StoredProcedure, spName, commandTimeout, commandParameters);
            }
            else
            {
                // Otherwise we can just call the SP without params
                // 否则 我们仅仅只能调用没有参数的SP

                return ExecuteReader(transaction, CommandType.StoredProcedure, spName, commandTimeout);
            }
        }

        /// <summary>
        ///     这个enum用来指出这个连接是否被调用者提供,或者被SqlHelpe创建,
        ///     以便于我们在调用ExecuteReader()时，可以用恰当的命令行为
        /// </summary>
        private enum OracleConnectionOwnership
        {
            // <summary>Connection is owned and managed by SqlHelper</summary>
            /// <summary>
            ///     连接被SqlHelper管理和拥有
            /// </summary>
            Internal,
            // <summary>Connection is owned and managed by the caller</summary>
            /// <summary>连接被调用者管理和拥有</summary>
            External
        }

        #endregion ExecuteReader

        #region ExecuteScalar

        /// <summary>
        ///     执行一个Sql命令(返回一个1x1结果集合并且不返回参数),这个命令是依附于指定了连接字符串的数据库
        /// </summary>
        /// <param name="connectionString">一个有效的Sql连接字符串</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令</param>
        /// <returns>一个包含由命令产生的1x1结果集合中的值的对象</returns>
        public static object ExecuteScalar(string connectionString, CommandType commandType, string commandText)
        {
            // Pass through the call providing null for the set of OracleParameters
            // 通过一个为Sql参数提供null值的调用
            return ExecuteScalar(connectionString, commandType, commandText, null);
        }

        /// <summary>
        ///     执行一个使用提供参数的Sql命令(返回一个结果集合并且不返回参数),这个命令是依附于指定了连接字符串的数据库
        /// </summary>
        /// <param name="connectionString">一个有效的Sql连接 字符串</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令。</param>
        /// <param name="commandParameters">用于执行命令的Sql参数数组</param>
        /// <returns>一个包含由命令产生的1x1结果集合中的值的对象</returns>
        public static object ExecuteScalar(string connectionString, CommandType commandType, string commandText,
                                           params OracleParameter[] commandParameters)
        {
            if (connectionString == null || connectionString.Length == 0)
                throw new ArgumentNullException("connectionString");
            // Create & open a OracleConnection, and dispose of it after we are done
            // 创建并且打开一个Sql连接，用完把它释放掉


            using (var connection = new OracleConnection(connectionString))
            {
                connection.Open();

                // Call the overload that takes a connection in place of the connection string
                // 调用这个在连接字符串中截取适当连接字符串的overload

                return ExecuteScalar(connection, commandType, commandText, commandParameters);
            }
        }

        /// <summary>
        ///     通过Sql命令(返回一个结果集合)来执行这个存储过程，
        ///     这个存储过程是为指定一个使用数据行列值作为存储过程参数值的连接字符串的数据库服务的。
        ///     这个方法为了发现存储过程(每一个第一次被调用的存储过程)的参数，它将会查询数据库, 并且按照参数的顺序给参数赋值。
        /// </summary>
        /// <param name="connectionString">一个有效的Sql连接字符串</param>
        /// <param name="spName">存储过程的名字</param>
        /// <param name="parameterValues">存储过程输入的值赋给这个对象数组</param>
        /// <returns>一个包含由命令产生的1x1结果集合中的值的对象</returns>
        public static object ExecuteScalar(string connectionString, string spName, params object[] parameterValues)
        {
            if (connectionString == null || connectionString.Length == 0)
                throw new ArgumentNullException("connectionString");
            if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");

            // If we receive parameter values, we need to figure out where they go
            // 如果我们接受到参数值，我们需要知道它们来自那里
            if ((parameterValues != null) && (parameterValues.Length > 0))
            {
                // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
                // 从存放着参数的缓存器中填充这个存储过程的参数
                OracleParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connectionString, spName);

                // Assign the provided values to these parameters based on parameter order
                // 按参数顺序给这些参数赋值
                AssignParameterValues(commandParameters, parameterValues);

                // Call the overload that takes an array of OracleParameters
                // 调用接受Sql参数数组的overload

                return ExecuteScalar(connectionString, CommandType.StoredProcedure, spName, commandParameters);
            }
            else
            {
                // Otherwise we can just call the SP without params
                // 否则，我们只能调用没有参数的SP
                return ExecuteScalar(connectionString, CommandType.StoredProcedure, spName);
            }
        }

        /// <summary>
        ///     执行一个Sql命令(返回一个结果集合并且不返回参数),这个命令是依附于的提供的Sql连接
        /// </summary>
        /// <param name="connection">一个有效的Sql连接</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令</param>
        /// <returns>一个包含由命令产生的1x1结果集合中的值的对象</returns>
        public static object ExecuteScalar(OracleConnection connection, CommandType commandType, string commandText)
        {
            // Pass through the call providing null for the set of OracleParameters
            // 通过一个为Sql参数提供null值的调用
            return ExecuteScalar(connection, commandType, commandText, null);
        }

        /// <summary>
        ///     使用提供的参数执行一个Sql命令(返回一个1x1结果集合)， 针对这个指定的Sql
        /// </summary>
        /// <param name="connection">一个有效的Sql连接</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令。</param>
        /// <param name="commandParameters">用于执行命令的Sql参数数组</param>
        /// <returns>一个包含由命令产生的1x1结果集合中的值的对象</returns>
        public static object ExecuteScalar(OracleConnection connection, CommandType commandType, string commandText,
                                           params OracleParameter[] commandParameters)
        {
            if (connection == null) throw new ArgumentNullException("connection");

            // Create a command and prepare it for execution
            // 创建一个命令并且准备执行它

            var cmd = new OracleCommand();

            bool mustCloseConnection = false;
            PrepareCommand(cmd, connection, null, commandType, commandText, commandParameters, out mustCloseConnection);

            // Execute the command & return the results
            // 执行这个命令并且返回结果
            object retval = cmd.ExecuteScalar();

            // Detach the OracleParameters from the command object, so they can be used again
            // 从命令对象中释放Sql参数，以便于它们可以再次被使用
            cmd.Parameters.Clear();

            //if (mustCloseConnection)
            connection.Close();

            return retval;
        }

        /// <summary>
        ///     通过Sql命令(返回一个结果集合)来执行这个存储过程，
        ///     这个存储过程是为指定一个使用数据行列值作为存储过程参数值的连接字符串的Sql连接服务的。
        ///     这个方法为了发现存储过程(每一个第一次被调用的存储过程)的参数，它将会查询数据库, 并且按照参数的顺序给参数赋值。
        /// </summary>
        /// <param name="connection">一个有效的Sql连接</param>
        /// <param name="spName">存储过程的名字</param>
        /// <param name="parameterValues">存储过程输入的值赋给这个对象数组</param>
        /// <returns>一个包含由命令产生的1x1结果集合中的值的对象</returns>
        public static object ExecuteScalar(OracleConnection connection, string spName, params object[] parameterValues)
        {
            if (connection == null) throw new ArgumentNullException("connection");
            if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");

            // If we receive parameter values, we need to figure out where they go
            // 如果我们接受到参数值，我们需要知道它们来自那里

            if ((parameterValues != null) && (parameterValues.Length > 0))
            {
                // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
                // 从存放着参数的缓存器中填充这个存储过程的参数
                OracleParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connection, spName);

                // Assign the provided values to these parameters based on parameter order
                // 按参数顺序给这些参数赋值
                AssignParameterValues(commandParameters, parameterValues);

                // Call the overload that takes an array of OracleParameters
                // 调用接受Sql参数数组的overload
                return ExecuteScalar(connection, CommandType.StoredProcedure, spName, commandParameters);
            }
            else
            {
                // Otherwise we can just call the SP without params
                // 否则，我们只能调用没有参数的SP
                return ExecuteScalar(connection, CommandType.StoredProcedure, spName);
            }
        }

        /// <summary>
        ///     执行一个Sql命令（返回一个1x1结果集合并且不带参数)，针对这个提供的Sql事务
        /// </summary>
        /// <param name="transaction">一个有效的Sql事务</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令</param>
        /// <returns>一个包含由命令产生的1x1结果集合中的值的对象</returns>
        public static object ExecuteScalar(OracleTransaction transaction, CommandType commandType, string commandText)
        {
            // Pass through the call providing null for the set of OracleParameters
            // 通过一个为Sql参数提供null值的调用
            return ExecuteScalar(transaction, commandType, commandText, null);
        }

        /// <summary>
        ///     使用提供的参数执行一个Sql命令(返回一个1x1结果集合)，针对这个指定的Sql事务
        /// </summary>
        /// <param name="transaction">一个有效的Sql事务</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令</param>
        /// <param name="commandParameters">用于执行命令的Sql参数数组</param>
        /// <returns>一个包含由命令产生的1x1结果集合中的值的对象</returns>
        public static object ExecuteScalar(OracleTransaction transaction, CommandType commandType, string commandText,
                                           params OracleParameter[] commandParameters)
        {
            if (transaction == null) throw new ArgumentNullException("transaction");
            if (transaction != null && transaction.Connection == null)
                throw new ArgumentException(
                    "The transaction was rollbacked or commited, please provide an open transaction.", "transaction");

            // Create a command and prepare it for execution
            // 创建一个命令并且准备执行它
            var cmd = new OracleCommand();
            bool mustCloseConnection = false;
            PrepareCommand(cmd, transaction.Connection, transaction, commandType, commandText, commandParameters,
                           out mustCloseConnection);

            // Execute the command & return the results
            // 执行一个命令并且返回一个结果
            object retval = cmd.ExecuteScalar();

            // Detach the OracleParameters from the command object, so they can be used again
            // 从对象命令中关闭Sql参数，以便于它们可以再次被使用
            cmd.Parameters.Clear();
            return retval;
        }

        /// <summary>
        ///     通过一个返回1x1结果集合的sql命令来执行一个提供了参数值的存储过程，针对指定的Sql事务。
        ///     这个方法为了发现存储过程(每一个存储过程第一次被调用)的参数，它将会查询数据库并且按照参数顺序给参数赋值。
        /// </summary>
        /// <param name="transaction">一个有效的事务</param>
        /// <param name="spName">存储过程的名字</param>
        /// <param name="parameterValues">存储过程输入的值赋给这个对象数组</param>
        /// <returns>一个包含由命令产生的1x1结果集合中的值的对象</returns>
        public static object ExecuteScalar(OracleTransaction transaction, string spName, params object[] parameterValues)
        {
            if (transaction == null) throw new ArgumentNullException("transaction");
            if (transaction != null && transaction.Connection == null)
                throw new ArgumentException(
                    "The transaction was rollbacked or commited, please provide an open transaction.", "transaction");
            if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");

            // If we receive parameter values, we need to figure out where they go
            // 如果我们接受到参数值，我们需要知道它们来自那里
            if ((parameterValues != null) && (parameterValues.Length > 0))
            {
                // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
                // 从存放着参数的缓存器中填充这个存储过程的参数
                OracleParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(transaction.Connection,
                                                                                                spName);

                // Assign the provided values to these parameters based on parameter order
                // 按参数顺序给这些参数赋值
                AssignParameterValues(commandParameters, parameterValues);

                // Call the overload that takes an array of OracleParameters
                // 调用接受Sql参数数组的overload
                return ExecuteScalar(transaction, CommandType.StoredProcedure, spName, commandParameters);
            }
            else
            {
                // Otherwise we can just call the SP without params
                // 否则，我们只能调用没有参数的SP
                return ExecuteScalar(transaction, CommandType.StoredProcedure, spName);
            }
        }

        /// <summary>
        ///     执行一个Sql命令(返回一个1x1结果集合并且不返回参数),这个命令是依附于指定了连接字符串的数据库
        /// </summary>
        /// <param name="connectionString">一个有效的Sql连接字符串</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <returns>一个包含由命令产生的1x1结果集合中的值的对象</returns>
        public static object ExecuteScalar(string connectionString, CommandType commandType, string commandText,
                                           int commandTimeout)
        {
            // Pass through the call providing null for the set of OracleParameters
            // 通过一个为Sql参数提供null值的调用
            return ExecuteScalar(connectionString, commandType, commandText, commandTimeout, null);
        }

        /// <summary>
        ///     执行一个使用提供参数的Sql命令(返回一个结果集合并且不返回参数),这个命令是依附于指定了连接字符串的数据库
        /// </summary>
        /// <param name="connectionString">一个有效的Sql连接 字符串</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令。</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <param name="commandParameters">用于执行命令的Sql参数数组</param>
        /// <returns>一个包含由命令产生的1x1结果集合中的值的对象</returns>
        public static object ExecuteScalar(string connectionString, CommandType commandType, string commandText,
                                           int commandTimeout, params OracleParameter[] commandParameters)
        {
            if (connectionString == null || connectionString.Length == 0)
                throw new ArgumentNullException("connectionString");
            // Create & open a OracleConnection, and dispose of it after we are done
            // 创建并且打开一个Sql连接，用完把它释放掉


            using (var connection = new OracleConnection(connectionString))
            {
                connection.Open();

                // Call the overload that takes a connection in place of the connection string
                // 调用这个在连接字符串中截取适当连接字符串的overload

                return ExecuteScalar(connection, commandType, commandText, commandTimeout, commandParameters);
            }
        }

        /// <summary>
        ///     通过Sql命令(返回一个结果集合)来执行这个存储过程，
        ///     这个存储过程是为指定一个使用数据行列值作为存储过程参数值的连接字符串的数据库服务的。
        ///     这个方法为了发现存储过程(每一个第一次被调用的存储过程)的参数，它将会查询数据库, 并且按照参数的顺序给参数赋值。
        /// </summary>
        /// <param name="connectionString">一个有效的Sql连接字符串</param>
        /// <param name="spName">存储过程的名字</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <param name="parameterValues">存储过程输入的值赋给这个对象数组</param>
        /// <returns>一个包含由命令产生的1x1结果集合中的值的对象</returns>
        public static object ExecuteScalar(string connectionString, string spName, int commandTimeout,
                                           params object[] parameterValues)
        {
            if (connectionString == null || connectionString.Length == 0)
                throw new ArgumentNullException("connectionString");
            if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");

            // If we receive parameter values, we need to figure out where they go
            // 如果我们接受到参数值，我们需要知道它们来自那里
            if ((parameterValues != null) && (parameterValues.Length > 0))
            {
                // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
                // 从存放着参数的缓存器中填充这个存储过程的参数
                OracleParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connectionString, spName);

                // Assign the provided values to these parameters based on parameter order
                // 按参数顺序给这些参数赋值
                AssignParameterValues(commandParameters, parameterValues);

                // Call the overload that takes an array of OracleParameters
                // 调用接受Sql参数数组的overload

                return ExecuteScalar(connectionString, CommandType.StoredProcedure, spName, commandTimeout,
                                     commandParameters);
            }
            else
            {
                // Otherwise we can just call the SP without params
                // 否则，我们只能调用没有参数的SP
                return ExecuteScalar(connectionString, CommandType.StoredProcedure, spName, commandTimeout);
            }
        }

        /// <summary>
        ///     执行一个Sql命令(返回一个结果集合并且不返回参数),这个命令是依附于的提供的Sql连接
        /// </summary>
        /// <param name="connection">一个有效的Sql连接</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <returns>一个包含由命令产生的1x1结果集合中的值的对象</returns>
        public static object ExecuteScalar(OracleConnection connection, CommandType commandType, string commandText,
                                           int commandTimeout)
        {
            // Pass through the call providing null for the set of OracleParameters
            // 通过一个为Sql参数提供null值的调用
            return ExecuteScalar(connection, commandType, commandText, commandTimeout, null);
        }

        /// <summary>
        ///     使用提供的参数执行一个Sql命令(返回一个1x1结果集合)， 针对这个指定的Sql
        /// </summary>
        /// <param name="connection">一个有效的Sql连接</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令。</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <param name="commandParameters">用于执行命令的Sql参数数组</param>
        /// <returns>一个包含由命令产生的1x1结果集合中的值的对象</returns>
        public static object ExecuteScalar(OracleConnection connection, CommandType commandType, string commandText,
                                           int commandTimeout, params OracleParameter[] commandParameters)
        {
            if (connection == null) throw new ArgumentNullException("connection");

            // Create a command and prepare it for execution
            // 创建一个命令并且准备执行它

            var cmd = new OracleCommand();

            bool mustCloseConnection = false;
            PrepareCommand(cmd, connection, null, commandType, commandText, commandTimeout, commandParameters,
                           out mustCloseConnection);

            // Execute the command & return the results
            // 执行这个命令并且返回结果
            object retval = cmd.ExecuteScalar();

            // Detach the OracleParameters from the command object, so they can be used again
            // 从命令对象中释放Sql参数，以便于它们可以再次被使用
            cmd.Parameters.Clear();

            if (mustCloseConnection)
                connection.Close();

            return retval;
        }

        /// <summary>
        ///     通过Sql命令(返回一个结果集合)来执行这个存储过程，
        ///     这个存储过程是为指定一个使用数据行列值作为存储过程参数值的连接字符串的Sql连接服务的。
        ///     这个方法为了发现存储过程(每一个第一次被调用的存储过程)的参数，它将会查询数据库, 并且按照参数的顺序给参数赋值。
        /// </summary>
        /// <param name="connection">一个有效的Sql连接</param>
        /// <param name="spName">存储过程的名字</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <param name="parameterValues">存储过程输入的值赋给这个对象数组</param>
        /// <returns>一个包含由命令产生的1x1结果集合中的值的对象</returns>
        public static object ExecuteScalar(OracleConnection connection, string spName, int commandTimeout,
                                           params object[] parameterValues)
        {
            if (connection == null) throw new ArgumentNullException("connection");
            if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");

            // If we receive parameter values, we need to figure out where they go
            // 如果我们接受到参数值，我们需要知道它们来自那里

            if ((parameterValues != null) && (parameterValues.Length > 0))
            {
                // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
                // 从存放着参数的缓存器中填充这个存储过程的参数
                OracleParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connection, spName);

                // Assign the provided values to these parameters based on parameter order
                // 按参数顺序给这些参数赋值
                AssignParameterValues(commandParameters, parameterValues);

                // Call the overload that takes an array of OracleParameters
                // 调用接受Sql参数数组的overload
                return ExecuteScalar(connection, CommandType.StoredProcedure, spName, commandTimeout, commandParameters);
            }
            else
            {
                // Otherwise we can just call the SP without params
                // 否则，我们只能调用没有参数的SP
                return ExecuteScalar(connection, CommandType.StoredProcedure, spName, commandTimeout);
            }
        }

        /// <summary>
        ///     执行一个Sql命令（返回一个1x1结果集合并且不带参数)，针对这个提供的Sql事务
        /// </summary>
        /// <param name="transaction">一个有效的Sql事务</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <returns>一个包含由命令产生的1x1结果集合中的值的对象</returns>
        public static object ExecuteScalar(OracleTransaction transaction, CommandType commandType, string commandText,
                                           int commandTimeout)
        {
            // Pass through the call providing null for the set of OracleParameters
            // 通过一个为Sql参数提供null值的调用
            return ExecuteScalar(transaction, commandType, commandText, commandTimeout, null);
        }

        /// <summary>
        ///     使用提供的参数执行一个Sql命令(返回一个1x1结果集合)，针对这个指定的Sql事务
        /// </summary>
        /// <param name="transaction">一个有效的Sql事务</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <param name="commandParameters">用于执行命令的Sql参数数组</param>
        /// <returns>一个包含由命令产生的1x1结果集合中的值的对象</returns>
        public static object ExecuteScalar(OracleTransaction transaction, CommandType commandType, string commandText,
                                           int commandTimeout, params OracleParameter[] commandParameters)
        {
            if (transaction == null) throw new ArgumentNullException("transaction");
            if (transaction != null && transaction.Connection == null)
                throw new ArgumentException(
                    "The transaction was rollbacked or commited, please provide an open transaction.", "transaction");

            // Create a command and prepare it for execution
            // 创建一个命令并且准备执行它
            var cmd = new OracleCommand();
            bool mustCloseConnection = false;
            PrepareCommand(cmd, transaction.Connection, transaction, commandType, commandText, commandTimeout,
                           commandParameters, out mustCloseConnection);

            // Execute the command & return the results
            // 执行一个命令并且返回一个结果
            object retval = cmd.ExecuteScalar();

            // Detach the OracleParameters from the command object, so they can be used again
            // 从对象命令中关闭Sql参数，以便于它们可以再次被使用
            cmd.Parameters.Clear();
            return retval;
        }

        /// <summary>
        ///     通过一个返回1x1结果集合的sql命令来执行一个提供了参数值的存储过程，针对指定的Sql事务。
        ///     这个方法为了发现存储过程(每一个存储过程第一次被调用)的参数，它将会查询数据库并且按照参数顺序给参数赋值。
        /// </summary>
        /// <param name="transaction">一个有效的事务</param>
        /// <param name="spName">存储过程的名字</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <param name="parameterValues">存储过程输入的值赋给这个对象数组</param>
        /// <returns>一个包含由命令产生的1x1结果集合中的值的对象</returns>
        public static object ExecuteScalar(OracleTransaction transaction, string spName, int commandTimeout,
                                           params object[] parameterValues)
        {
            if (transaction == null) throw new ArgumentNullException("transaction");
            if (transaction != null && transaction.Connection == null)
                throw new ArgumentException(
                    "The transaction was rollbacked or commited, please provide an open transaction.", "transaction");
            if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");

            // If we receive parameter values, we need to figure out where they go
            // 如果我们接受到参数值，我们需要知道它们来自那里
            if ((parameterValues != null) && (parameterValues.Length > 0))
            {
                // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
                // 从存放着参数的缓存器中填充这个存储过程的参数
                OracleParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(transaction.Connection,
                                                                                                spName);

                // Assign the provided values to these parameters based on parameter order
                // 按参数顺序给这些参数赋值
                AssignParameterValues(commandParameters, parameterValues);

                // Call the overload that takes an array of OracleParameters
                // 调用接受Sql参数数组的overload
                return ExecuteScalar(transaction, CommandType.StoredProcedure, spName, commandTimeout, commandParameters);
            }
            else
            {
                // Otherwise we can just call the SP without params
                // 否则，我们只能调用没有参数的SP
                return ExecuteScalar(transaction, CommandType.StoredProcedure, spName, commandTimeout);
            }
        }

        #endregion ExecuteScalar

        #region ExecuteXmlReader

        //public static XmlReader ExecuteXmlReader(OracleConnection connection, CommandType commandType, string commandText)
        //{
        //    // Pass through the call providing null for the set of OracleParameters
        //    // 通过一个为sql参数提供null值的调用
        //    return ExecuteXmlReader(connection, commandType, commandText, (OracleParameter[])null);
        //}
        //public static XmlReader ExecuteXmlReader(OracleConnection connection, CommandType commandType, string commandText, params OracleParameter[] commandParameters)
        //{
        //    if (connection == null) throw new ArgumentNullException("connection");
        //    bool mustCloseConnection = false;
        //    // Create a command and prepare it for execution
        //    // 创建一个命令并且准备执行它
        //    OracleCommand cmd = new OracleCommand();
        //    try
        //    {
        //        PrepareCommand(cmd, connection, (OracleTransaction)null, commandType, commandText, commandParameters, out mustCloseConnection);
        //        // Create the DataAdapter & DataSet
        //        // 创建DataAdapter & DataSet
        //        XmlReader retval = cmd.ExecuteReader();
        //        //  XmlReader retval = cmd.ExecuteReader();
        //        // Detach the OracleParameters from the command object, so they can be used again
        //        // 从对象命令中关闭Sql参数，以便于它们可以再次被使用
        //        cmd.Parameters.Clear();
        //        return retval;
        //    }
        //    catch
        //    {
        //        if (mustCloseConnection)
        //            connection.Close();
        //        throw;
        //    }
        //}
        //public static XmlReader ExecuteXmlReader(OracleConnection connection, string spName, params object[] parameterValues)
        //{
        //    if (connection == null) throw new ArgumentNullException("connection");
        //    if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");
        //    // If we receive parameter values, we need to figure out where they go
        //    // 如果我们接受到参数值，我们需要知道它们来自那里
        //    if ((parameterValues != null) && (parameterValues.Length > 0))
        //    {
        //        // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
        //        // 从存放着参数的缓存器中填充这个存储过程的参数
        //        OracleParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connection, spName);
        //        // Assign the provided values to these parameters based on parameter order
        //        // 按参数顺序给这些参数赋值
        //        AssignParameterValues(commandParameters, parameterValues);
        //        // Call the overload that takes an array of OracleParameters
        //        // 调用接受Sql参数数组的overload
        //        return ExecuteXmlReader(connection, CommandType.StoredProcedure, spName, commandParameters);
        //    }
        //    else
        //    {
        //        // Otherwise we can just call the SP without params
        //        // 否则，我们只能调用没有参数的SP
        //        return ExecuteXmlReader(connection, CommandType.StoredProcedure, spName);
        //    }
        //}
        //public static XmlReader ExecuteXmlReader(OracleTransaction transaction, CommandType commandType, string commandText)
        //{
        //    // Pass through the call providing null for the set of OracleParameters
        //    // 通过一个为Sql参数提供null值的调用
        //    return ExecuteXmlReader(transaction, commandType, commandText, (OracleParameter[])null);
        //}
        //public static XmlReader ExecuteXmlReader(OracleTransaction transaction, CommandType commandType, string commandText, params OracleParameter[] commandParameters)
        //{
        //    if (transaction == null) throw new ArgumentNullException("transaction");
        //    if (transaction != null && transaction.Connection == null) throw new ArgumentException("The transaction was rollbacked or commited, please provide an open transaction.", "transaction");
        //    // Create a command and prepare it for execution
        //    // 创建一个命令并且准备执行它
        //    OracleCommand cmd = new OracleCommand();
        //    bool mustCloseConnection = false;
        //    PrepareCommand(cmd, transaction.Connection, transaction, commandType, commandText, commandParameters, out mustCloseConnection);
        //    // Create the DataAdapter & DataSet
        //    // 创建DataAdapter & DataSet
        //    XmlReader retval = cmd.ExecuteXmlReader();
        //    // Detach the OracleParameters from the command object, so they can be used again
        //    // 从对象命令中关闭Sql参数，以便于它们可以再次被使用
        //    cmd.Parameters.Clear();
        //    return retval;
        //}
        //public static XmlReader ExecuteXmlReader(OracleTransaction transaction, string spName, params object[] parameterValues)
        //{
        //    if (transaction == null) throw new ArgumentNullException("transaction");
        //    if (transaction != null && transaction.Connection == null) throw new ArgumentException("The transaction was rollbacked or commited, please provide an open transaction.", "transaction");
        //    if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");
        //    // If we receive parameter values, we need to figure out where they go
        //    // 如果我们接受到参数值，我们需要知道它们来自那里
        //    if ((parameterValues != null) && (parameterValues.Length > 0))
        //    {
        //        // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
        //        // 从存放着参数的缓存器中填充这个存储过程的参数
        //        OracleParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(transaction.Connection, spName);
        //        // Assign the provided values to these parameters based on parameter order
        //        // 按参数顺序给这些参数赋值
        //        AssignParameterValues(commandParameters, parameterValues);
        //        // Call the overload that takes an array of OracleParameters
        //        // 调用接受Sql参数数组的overload
        //        return ExecuteXmlReader(transaction, CommandType.StoredProcedure, spName, commandParameters);
        //    }
        //    else
        //    {
        //        // Otherwise we can just call the SP without params
        //        // 否则，我们只能调用没有参数的SP
        //        return ExecuteXmlReader(transaction, CommandType.StoredProcedure, spName);
        //    }
        //}
        //public static XmlReader ExecuteXmlReader(OracleConnection connection, CommandType commandType, string commandText, int commandTimeout)
        //{
        //    // Pass through the call providing null for the set of OracleParameters
        //    // 通过一个为sql参数提供null值的调用
        //    return ExecuteXmlReader(connection, commandType, commandText, commandTimeout, (OracleParameter[])null);
        //}
        //public static XmlReader ExecuteXmlReader(OracleConnection connection, CommandType commandType, string commandText, int commandTimeout, params OracleParameter[] commandParameters)
        //{
        //    if (connection == null) throw new ArgumentNullException("connection");
        //    bool mustCloseConnection = false;
        //    // Create a command and prepare it for execution
        //    // 创建一个命令并且准备执行它
        //    OracleCommand cmd = new OracleCommand();
        //    try
        //    {
        //        PrepareCommand(cmd, connection, (OracleTransaction)null, commandType, commandText, commandTimeout, commandParameters, out mustCloseConnection);
        //        // Create the DataAdapter & DataSet
        //        // 创建DataAdapter & DataSet
        //        XmlReader retval = cmd.ExecuteXmlReader();
        //        // Detach the OracleParameters from the command object, so they can be used again
        //        // 从对象命令中关闭Sql参数，以便于它们可以再次被使用
        //        cmd.Parameters.Clear();
        //        return retval;
        //    }
        //    catch
        //    {
        //        if (mustCloseConnection)
        //            connection.Close();
        //        throw;
        //    }
        //}
        //public static XmlReader ExecuteXmlReader(OracleConnection connection, string spName, int commandTimeout, params object[] parameterValues)
        //{
        //    if (connection == null) throw new ArgumentNullException("connection");
        //    if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");
        //    // If we receive parameter values, we need to figure out where they go
        //    // 如果我们接受到参数值，我们需要知道它们来自那里
        //    if ((parameterValues != null) && (parameterValues.Length > 0))
        //    {
        //        // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
        //        // 从存放着参数的缓存器中填充这个存储过程的参数
        //        OracleParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connection, spName);
        //        // Assign the provided values to these parameters based on parameter order
        //        // 按参数顺序给这些参数赋值
        //        AssignParameterValues(commandParameters, parameterValues);
        //        // Call the overload that takes an array of OracleParameters
        //        // 调用接受Sql参数数组的overload
        //        return ExecuteXmlReader(connection, CommandType.StoredProcedure, spName, commandTimeout, commandParameters);
        //    }
        //    else
        //    {
        //        // Otherwise we can just call the SP without params
        //        // 否则，我们只能调用没有参数的SP
        //        return ExecuteXmlReader(connection, CommandType.StoredProcedure, spName, commandTimeout);
        //    }
        //}
        //public static XmlReader ExecuteXmlReader(OracleTransaction transaction, CommandType commandType, string commandText, int commandTimeout)
        //{
        //    // Pass through the call providing null for the set of OracleParameters
        //    // 通过一个为Sql参数提供null值的调用
        //    return ExecuteXmlReader(transaction, commandType, commandText, commandTimeout, (OracleParameter[])null);
        //}
        //public static XmlReader ExecuteXmlReader(OracleTransaction transaction, CommandType commandType, string commandText, int commandTimeout, params OracleParameter[] commandParameters)
        //{
        //    if (transaction == null) throw new ArgumentNullException("transaction");
        //    if (transaction != null && transaction.Connection == null) throw new ArgumentException("The transaction was rollbacked or commited, please provide an open transaction.", "transaction");
        //    // Create a command and prepare it for execution
        //    // 创建一个命令并且准备执行它
        //    OracleCommand cmd = new OracleCommand();
        //    bool mustCloseConnection = false;
        //    PrepareCommand(cmd, transaction.Connection, transaction, commandType, commandText, commandTimeout, commandParameters, out mustCloseConnection);
        //    // Create the DataAdapter & DataSet
        //    // 创建DataAdapter & DataSet
        //    XmlReader retval = cmd.ExecuteXmlReader();
        //    // Detach the OracleParameters from the command object, so they can be used again
        //    // 从对象命令中关闭Sql参数，以便于它们可以再次被使用
        //    cmd.Parameters.Clear();
        //    return retval;
        //}
        //public static XmlReader ExecuteXmlReader(OracleTransaction transaction, string spName, int commandTimeout, params object[] parameterValues)
        //{
        //    if (transaction == null) throw new ArgumentNullException("transaction");
        //    if (transaction != null && transaction.Connection == null) throw new ArgumentException("The transaction was rollbacked or commited, please provide an open transaction.", "transaction");
        //    if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");
        //    // If we receive parameter values, we need to figure out where they go
        //    // 如果我们接受到参数值，我们需要知道它们来自那里
        //    if ((parameterValues != null) && (parameterValues.Length > 0))
        //    {
        //        // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
        //        // 从存放着参数的缓存器中填充这个存储过程的参数
        //        OracleParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(transaction.Connection, spName);
        //        // Assign the provided values to these parameters based on parameter order
        //        // 按参数顺序给这些参数赋值
        //        AssignParameterValues(commandParameters, parameterValues);
        //        // Call the overload that takes an array of OracleParameters
        //        // 调用接受Sql参数数组的overload
        //        return ExecuteXmlReader(transaction, CommandType.StoredProcedure, spName, commandTimeout, commandParameters);
        //    }
        //    else
        //    {
        //        // Otherwise we can just call the SP without params
        //        // 否则，我们只能调用没有参数的SP
        //        return ExecuteXmlReader(transaction, CommandType.StoredProcedure, spName, commandTimeout);
        //    }
        //}

        #endregion ExecuteXmlReader

        #region FillDataset

        /// <summary>
        ///     通过Sql命令(返回一个结果集合)来执行这个存储过程，
        ///     这个存储过程是为指定一个使用数据行列值作为存储过程参数值的连接字符串的Sql事务服务的。
        ///     这个方法为了发现存储过程(每一个第一次被调用的存储过程)的参数，它将会查询数据库, 并且按照参数的顺序给参数赋值。
        /// </summary>
        /// <param name="transaction">一个有效的Sql事务</param>
        /// <param name="spName">存储过程的名字</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <param name="parameterValues">把存储过程的输入参数赋给对象数组</param>
        static void FillDataset(OracleTransaction transaction, string spName, int commandTimeout, params OracleParameter[] parameterValues)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        ///     执行一个Sql命令(返回一个结果集合并且不返回参数),这个命令是依附于指定了连接字符串的数
        /// </summary>
        /// <param name="connectionString">一个有效的Sql连接字符串</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令</param>
        /// <param name="dataSet">一个包含由命令产生结果集合的dataset</param>
        /// <param name="tableNames">
        ///     这个数组用于创建一个允许DataTables通过用户定义名字(可能是实际的表名)来被表图参考。
        /// </param>
        public static void FillDataset(string connectionString, CommandType commandType, string commandText,
                                       DataSet dataSet, string[] tableNames)
        {
            if (connectionString == null || connectionString.Length == 0)
                throw new ArgumentNullException("connectionString");
            if (dataSet == null) throw new ArgumentNullException("dataSet");

            // Create & open a OracleConnection, and dispose of it after we are done
            // 创建和打开一个Sql连接，在我们不用它时把它释放掉
            using (var connection = new OracleConnection(connectionString))
            {
                connection.Open();

                // Call the overload that takes a connection in place of the connection string
                // 调用一个从连接字符串中截取一个恰当的连接的overload
                FillDataset(connection, commandType, commandText, dataSet, tableNames);
            }
        }

        /// <summary>
        ///     对于一个指定的Sql连接，使用提供的参数执行一个返回结果集合的Sql命令
        /// </summary>
        /// <param name="connectionString">一个有效的Sql连接字符串</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令</param>
        /// <param name="commandParameters">执行命令的Sql参数数组</param>
        /// <param name="dataSet">一个包含由命令产生结果集合的dataset</param>
        /// <param name="tableNames">
        ///     这个数组用于创建一个允许DataTables通过用户定义名字(可能是实际的表名)来被表图参考。
        /// </param>
        public static void FillDataset(string connectionString, CommandType commandType,
                                       string commandText, DataSet dataSet, string[] tableNames,
                                       params OracleParameter[] commandParameters)
        {
            if (connectionString == null || connectionString.Length == 0)
                throw new ArgumentNullException("connectionString");
            if (dataSet == null) throw new ArgumentNullException("dataSet");
            // Create & open a OracleConnection, and dispose of it after we are done
            // 创建和打开一个Sql连接，在我们不用它时把它释放掉
            using (var connection = new OracleConnection(connectionString))
            {
                connection.Open();

                // Call the overload that takes a connection in place of the connection string
                // 调用一个从连接字符串中截取一个恰当的连接的overload

                FillDataset(connection, commandType, commandText, dataSet, tableNames, commandParameters);
            }
        }

        /// <summary>
        ///     通过Sql命令(返回一个结果集合)来执行这个存储过程，
        ///     这个存储过程是为指定一个使用数据行列值作为存储过程参数值的连接字符串的数据库服务的。
        ///     这个方法为了发现存储过程(每一个第一次被调用的存储过程)的参数，它将会查询数据库, 并且按照参数的顺序给参数赋值。
        /// </summary>
        /// <remarks>
        ///     这个方法不提供输出参数或者存储过程返回值的存取
        ///     e.g.:
        ///     FillDataset(connString, CommandType.StoredProcedure, "GetOrders", ds, new string[] {"orders"}, 24);
        /// </remarks>
        /// <param name="connectionString">一个有效的Sql连接字符串</param>
        /// <param name="spName">命令类型(存储过程，文本，等)。</param>
        /// <param name="dataSet">一个包含由命令产生结果集合的dataset</param>
        /// <param name="tableNames">
        ///     这个数组用于创建一个允许DataTables通过用户定义名字(可能是实际的表名)来被table mapping参考。
        /// </param>
        /// <param name="parameterValues">把存储过程的输入参数赋给对象数组</param>
        public static void FillDataset(string connectionString, string spName,
                                       DataSet dataSet, string[] tableNames,
                                       params object[] parameterValues)
        {
            if (connectionString == null || connectionString.Length == 0)
                throw new ArgumentNullException("connectionString");
            if (dataSet == null) throw new ArgumentNullException("dataSet");
            // Create & open a OracleConnection, and dispose of it after we are done
            // 创建和打开一个Sql连接，在我们不用它时把它释放掉
            using (var connection = new OracleConnection(connectionString))
            {
                connection.Open();

                // Call the overload that takes a connection in place of the connection string
                // 调用一个从连接字符串中截取一个恰当的连接的overload
                FillDataset(connection, spName, dataSet, tableNames, parameterValues);
            }
        }

        /// <summary>
        ///     对于一个指定的Sql连接，使用提供的参数执行一个返回结果集合的Sql命令
        /// </summary>
        /// <param name="connection">一个有效的Sql连接</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)。</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令。</param>
        /// <param name="dataSet">一个包含由命令产生结果集合的dataset</param>
        /// <param name="tableNames">
        ///     这个数组用于创建一个允许DataTables通过用户定义名字(可能是实际的表名)来被table mapping参考。
        /// </param>
        public static void FillDataset(OracleConnection connection, CommandType commandType,
                                       string commandText, DataSet dataSet, string[] tableNames)
        {
            FillDataset(connection, commandType, commandText, dataSet, tableNames, null);
        }

        /// <summary>
        ///     对于一个指定的Sql连接，使用提供的参数执行一个返回结果集合的Sql命令
        /// </summary>
        /// <param name="connection">一个有效的Sql连接</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)。</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令。</param>
        /// <param name="dataSet">一个包含由命令产生结果集合的dataset</param>
        /// <param name="tableNames">
        ///     这个数组用于创建一个允许DataTables通过用户定义名字(可能是实际的表名)来被table mapping参考。
        /// </param>
        /// <param name="commandParameters">An array of SqlParamters used to execute the command</param>
        public static void FillDataset(OracleConnection connection, CommandType commandType,
                                       string commandText, DataSet dataSet, string[] tableNames,
                                       params OracleParameter[] commandParameters)
        {
            FillDataset(connection, null, commandType, commandText, dataSet, tableNames, commandParameters);
        }

        /// <summary>
        ///     通过Sql命令(返回一个结果集合)来执行这个存储过程，
        ///     这个存储过程是为指定一个使用数据行列值作为存储过程参数值的连接字符串的Sql 连接服务的。
        ///     这个方法为了发现存储过程(每一个第一次被调用的存储过程)的参数，它将会查询数据库, 并且按照参数的顺序给参数赋值。
        /// </summary>
        /// <param name="connection">一个有效的Sql连接</param>
        /// <param name="spName">命令类型(存储过程，文本，等)。</param>
        /// <param name="dataSet">一个包含由命令产生结果集合的dataset</param>
        /// <param name="tableNames">
        ///     这个数组用于创建一个允许DataTables通过用户定义名字(可能是实际的表名)来被table mapping参考。
        /// </param>
        /// <param name="parameterValues">An array of objects to be assigned as the input values of the stored procedure</param>
        public static void FillDataset(OracleConnection connection, string spName,
                                       DataSet dataSet, string[] tableNames,
                                       params object[] parameterValues)
        {
            if (connection == null) throw new ArgumentNullException("connection");
            if (dataSet == null) throw new ArgumentNullException("dataSet");
            if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");

            // If we receive parameter values, we need to figure out where they go
            // 如果接受到参数的值，我们需要知道它们来自那里
            if ((parameterValues != null) && (parameterValues.Length > 0))
            {
                // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
                // 从存放着参数的缓存器中填充这个存储过程的参数

                OracleParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connection, spName);

                // Assign the provided values to these parameters based on parameter order
                // 按参数顺序给这些参数赋值

                AssignParameterValues(commandParameters, parameterValues);

                // Call the overload that takes an array of OracleParameters
                // 调用接受Sql参数数组的overload

                FillDataset(connection, CommandType.StoredProcedure, spName, dataSet, tableNames, commandParameters);
            }
            else
            {
                // Otherwise we can just call the SP without params
                // 否则，我们只能调用没有参数的SP
                FillDataset(connection, CommandType.StoredProcedure, spName, dataSet, tableNames);
            }
        }

        /// <summary>
        ///     对于这个提供的Sql事务执行一个没有返回结果集合和没有参数的Sql命令。
        /// </summary>
        /// <param name="transaction">一个有效的Sql事务</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)。</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令。</param>
        /// <param name="dataSet">一个包含由命令产生结果集合的dataset</param>
        /// <param name="tableNames">
        ///     这个数组用于创建一个允许DataTables通过用户定义名字(可能是实际的表名)来被table mapping参考。
        /// </param>
        public static void FillDataset(OracleTransaction transaction, CommandType commandType,
                                       string commandText,
                                       DataSet dataSet, string[] tableNames)
        {
            FillDataset(transaction, commandType, commandText, dataSet, tableNames, null);
        }

        /// <summary>
        ///     对于指定的Sql事务使用提供的参数执行返回结果集合的Sql命令。
        /// </summary>
        /// <param name="transaction">一个有效的Sql事务</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)。</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令</param>
        /// <param name="dataSet">一个包含由命令产生结果集合的dataset</param>
        /// <param name="tableNames">
        ///     这个数组用于创建一个允许DataTables通过用户定义名字(可能是实际的表名)来被table mapping参考。
        /// </param>
        /// <param name="commandParameters">用于执行命令的Sql数组参数</param>
        public static void FillDataset(OracleTransaction transaction, CommandType commandType,
                                       string commandText, DataSet dataSet, string[] tableNames,
                                       params OracleParameter[] commandParameters)
        {
            FillDataset(transaction.Connection, transaction, commandType, commandText, dataSet, tableNames,
                        commandParameters);
        }

        /// <summary>
        ///     通过Sql命令(返回一个结果集合)来执行这个存储过程，
        ///     这个存储过程是为指定一个使用数据行列值作为存储过程参数值的连接字符串的Sql 事务服务的。
        ///     这个方法为了发现存储过程(每一个第一次被调用的存储过程)的参数，它将会查询数据库, 并且按照参数的顺序给参数赋值。
        /// </summary>
        /// <param name="transaction">一个有效的Sql事务</param>
        /// <param name="spName">存储过程名字</param>
        /// <param name="dataSet">一个包含由命令产生结果集合的dataset</param>
        /// <param name="tableNames">
        ///     这个数组用于创建一个允许DataTables通过用户定义名字(可能是实际的表名)来被table mapping参考。
        /// </param>
        /// <param name="parameterValues">存储过程输入参数的值将赋给对象数组</param>
        public static void FillDataset(OracleTransaction transaction, string spName,
                                       DataSet dataSet, string[] tableNames,
                                       params object[] parameterValues)
        {
            if (transaction == null) throw new ArgumentNullException("transaction");
            if (transaction != null && transaction.Connection == null)
                throw new ArgumentException(
                    "The transaction was rollbacked or commited, please provide an open transaction.", "transaction");
            if (dataSet == null) throw new ArgumentNullException("dataSet");
            if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");

            // If we receive parameter values, we need to figure out where they go
            // 如果我们接受到参数的值，我们需要知道它们来自那里
            if ((parameterValues != null) && (parameterValues.Length > 0))
            {
                // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
                // 从存放着参数的缓存器中填充这个存储过程的参数

                OracleParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(transaction.Connection,
                                                                                                spName);

                // Assign the provided values to these parameters based on parameter order
                // 按参数顺序给这些参数赋值
                AssignParameterValues(commandParameters, parameterValues);

                // Call the overload that takes an array of OracleParameters
                // 调用接受Sql参数数组的overload
                FillDataset(transaction, CommandType.StoredProcedure, spName, dataSet, tableNames, commandParameters);
            }
            else
            {
                // Otherwise we can just call the SP without params
                // 否则，我们仅仅只能调用没有参数的SP
                FillDataset(transaction, CommandType.StoredProcedure, spName, dataSet, tableNames);
            }
        }

        /// <summary>
        ///     helper这个方法是一个执行Sql命令(返回结果集合)针对指定的Sql事务和使用参数的Sql连接对象。
        /// </summary>
        /// <param name="connection">一个有效的Sql连接</param>
        /// <param name="transaction">一个有效的Sql事务</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令</param>
        /// <param name="dataSet">一个包含由命令产生结果集合的dataset</param>
        /// <param name="tableNames">
        ///     这个数组用于创建一个允许DataTables通过用户定义名字(可能是实际的表名)来被表图参考。
        /// </param>
        /// <param name="commandParameters">An array of SqlParamters used to execute the command</param>
        private static void FillDataset(OracleConnection connection, OracleTransaction transaction,
                                        CommandType commandType,
                                        string commandText, DataSet dataSet, string[] tableNames,
                                        params OracleParameter[] commandParameters)
        {
            if (connection == null) throw new ArgumentNullException("connection");
            if (dataSet == null) throw new ArgumentNullException("dataSet");

            // Create a command and prepare it for execution
            // 创建一个命令，以用它来执行
            var command = new OracleCommand();
            bool mustCloseConnection = false;
            PrepareCommand(command, connection, transaction, commandType, commandText, commandParameters,
                           out mustCloseConnection);

            // Create the DataAdapter & DataSet
            // 创建DataAdapter & DataSet
            using (var dataAdapter = new OracleDataAdapter(command))
            {
                // Add the table mappings specified by the user
                // 增加一个用户指定的table mapping
                if (tableNames != null && tableNames.Length > 0)
                {
                    string tableName = "Table";
                    for (int index = 0; index < tableNames.Length; index++)
                    {
                        if (tableNames[index] == null || tableNames[index].Length == 0)
                            throw new ArgumentException(
                                "The tableNames parameter must contain a list of tables, a value was provided as null or empty string.",
                                "tableNames");
                        dataAdapter.TableMappings.Add(tableName, tableNames[index]);
                        tableName += (index + 1).ToString();
                    }
                }

                // Fill the DataSet using default values for DataTable names, etc
                // 使用默认的DataTable的名字，等来填充DataSet
                dataAdapter.Fill(dataSet);

                // Detach the OracleParameters from the command object, so they can be used again
                // 从命令对象中释放Sql参数，以便于它们可以再次被使用
                command.Parameters.Clear();
            }

            if (mustCloseConnection)
                connection.Close();
        }

        /// <summary>
        ///     执行一个Sql命令(返回一个结果集合并且不返回参数),这个命令是依附于指定了连接字符串的数
        /// </summary>
        /// <param name="connectionString">一个有效的Sql连接字符串</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <param name="dataSet">一个包含由命令产生结果集合的dataset</param>
        /// <param name="tableNames">
        ///     这个数组用于创建一个允许DataTables通过用户定义名字(可能是实际的表名)来被表图参考。
        /// </param>
        public static void FillDataset(string connectionString, CommandType commandType, string commandText,
                                       int commandTimeout, DataSet dataSet, string[] tableNames)
        {
            if (connectionString == null || connectionString.Length == 0)
                throw new ArgumentNullException("connectionString");
            if (dataSet == null) throw new ArgumentNullException("dataSet");

            // Create & open a OracleConnection, and dispose of it after we are done
            // 创建和打开一个Sql连接，在我们不用它时把它释放掉
            using (var connection = new OracleConnection(connectionString))
            {
                connection.Open();

                // Call the overload that takes a connection in place of the connection string
                // 调用一个从连接字符串中截取一个恰当的连接的overload
                FillDataset(connection, commandType, commandText, commandTimeout, dataSet, tableNames);
            }
        }

        /// <summary>
        ///     对于一个指定的Sql连接，使用提供的参数执行一个返回结果集合的Sql命令
        /// </summary>
        /// <param name="connectionString">一个有效的Sql连接字符串</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <param name="commandParameters">执行命令的Sql参数数组</param>
        /// <param name="dataSet">一个包含由命令产生结果集合的dataset</param>
        /// <param name="tableNames">
        ///     这个数组用于创建一个允许DataTables通过用户定义名字(可能是实际的表名)来被表图参考。
        /// </param>
        public static void FillDataset(string connectionString, CommandType commandType,
                                       string commandText, int commandTimeout, DataSet dataSet, string[] tableNames,
                                       params OracleParameter[] commandParameters)
        {
            if (connectionString == null || connectionString.Length == 0)
                throw new ArgumentNullException("connectionString");
            if (dataSet == null) throw new ArgumentNullException("dataSet");
            // Create & open a OracleConnection, and dispose of it after we are done
            // 创建和打开一个Sql连接，在我们不用它时把它释放掉
            using (var connection = new OracleConnection(connectionString))
            {
                connection.Open();

                // Call the overload that takes a connection in place of the connection string
                // 调用一个从连接字符串中截取一个恰当的连接的overload

                FillDataset(connection, commandType, commandText, commandTimeout, dataSet, tableNames, commandParameters);
            }
        }

        /// <summary>
        ///     通过Sql命令(返回一个结果集合)来执行这个存储过程，
        ///     这个存储过程是为指定一个使用数据行列值作为存储过程参数值的连接字符串的数据库服务的。
        ///     这个方法为了发现存储过程(每一个第一次被调用的存储过程)的参数，它将会查询数据库, 并且按照参数的顺序给参数赋值。
        /// </summary>
        /// <remarks>
        ///     这个方法不提供输出参数或者存储过程返回值的存取
        ///     e.g.:
        ///     FillDataset(connString, CommandType.StoredProcedure, "GetOrders", 30, ds, new string[] {"orders"}, 24);
        /// </remarks>
        /// <param name="connectionString">一个有效的Sql连接字符串</param>
        /// <param name="spName">命令类型(存储过程，文本，等)。</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <param name="dataSet">一个包含由命令产生结果集合的dataset</param>
        /// <param name="tableNames">
        ///     这个数组用于创建一个允许DataTables通过用户定义名字(可能是实际的表名)来被table mapping参考。
        /// </param>
        /// <param name="parameterValues">把存储过程的输入参数赋给对象数组</param>
        public static void FillDataset(string connectionString, string spName, int commandTimeout,
                                       DataSet dataSet, string[] tableNames,
                                       params object[] parameterValues)
        {
            if (connectionString == null || connectionString.Length == 0)
                throw new ArgumentNullException("connectionString");
            if (dataSet == null) throw new ArgumentNullException("dataSet");
            // Create & open a OracleConnection, and dispose of it after we are done
            // 创建和打开一个Sql连接，在我们不用它时把它释放掉
            using (var connection = new OracleConnection(connectionString))
            {
                connection.Open();

                // Call the overload that takes a connection in place of the connection string
                // 调用一个从连接字符串中截取一个恰当的连接的overload
                FillDataset(connection, spName, commandTimeout, dataSet, tableNames, parameterValues);
            }
        }

        /// <summary>
        ///     对于一个指定的Sql连接，使用提供的参数执行一个返回结果集合的Sql命令
        /// </summary>
        /// <param name="connection">一个有效的Sql连接</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)。</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令。</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <param name="dataSet">一个包含由命令产生结果集合的dataset</param>
        /// <param name="tableNames">
        ///     这个数组用于创建一个允许DataTables通过用户定义名字(可能是实际的表名)来被table mapping参考。
        /// </param>
        public static void FillDataset(OracleConnection connection, CommandType commandType,
                                       string commandText, int commandTimeout, DataSet dataSet, string[] tableNames)
        {
            FillDataset(connection, commandType, commandText, commandTimeout, dataSet, tableNames, null);
        }

        /// <summary>
        ///     对于一个指定的Sql连接，使用提供的参数执行一个返回结果集合的Sql命令
        /// </summary>
        /// <param name="connection">一个有效的Sql连接</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)。</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令。</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <param name="dataSet">一个包含由命令产生结果集合的dataset</param>
        /// <param name="tableNames">
        ///     这个数组用于创建一个允许DataTables通过用户定义名字(可能是实际的表名)来被table mapping参考。
        /// </param>
        /// <param name="commandParameters">An array of SqlParamters used to execute the command</param>
        public static void FillDataset(OracleConnection connection, CommandType commandType,
                                       string commandText, int commandTimeout, DataSet dataSet, string[] tableNames,
                                       params OracleParameter[] commandParameters)
        {
            FillDataset(connection, null, commandType, commandText, commandTimeout, dataSet, tableNames,
                        commandParameters);
        }

        /// <summary>
        ///     通过Sql命令(返回一个结果集合)来执行这个存储过程，
        ///     这个存储过程是为指定一个使用数据行列值作为存储过程参数值的连接字符串的Sql 连接服务的。
        ///     这个方法为了发现存储过程(每一个第一次被调用的存储过程)的参数，它将会查询数据库, 并且按照参数的顺序给参数赋值。
        /// </summary>
        /// <param name="connection">一个有效的Sql连接</param>
        /// <param name="spName">存储过程名称。</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <param name="dataSet">一个包含由命令产生结果集合的dataset</param>
        /// <param name="tableNames">
        ///     这个数组用于创建一个允许DataTables通过用户定义名字(可能是实际的表名)来被table mapping参考。
        /// </param>
        /// <param name="parameterValues">An array of objects to be assigned as the input values of the stored procedure</param>
        public static void FillDataset(OracleConnection connection, string spName, int commandTimeout,
                                       DataSet dataSet, string[] tableNames,
                                       params object[] parameterValues)
        {
            if (connection == null) throw new ArgumentNullException("connection");
            if (dataSet == null) throw new ArgumentNullException("dataSet");
            if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");

            // If we receive parameter values, we need to figure out where they go
            // 如果接受到参数的值，我们需要知道它们来自那里
            if ((parameterValues != null) && (parameterValues.Length > 0))
            {
                // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
                // 从存放着参数的缓存器中填充这个存储过程的参数

                OracleParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connection, spName);

                // Assign the provided values to these parameters based on parameter order
                // 按参数顺序给这些参数赋值

                AssignParameterValues(commandParameters, parameterValues);

                // Call the overload that takes an array of OracleParameters
                // 调用接受Sql参数数组的overload

                FillDataset(connection, CommandType.StoredProcedure, spName, commandTimeout, dataSet, tableNames,
                            commandParameters);
            }
            else
            {
                // Otherwise we can just call the SP without params
                // 否则，我们只能调用没有参数的SP
                FillDataset(connection, CommandType.StoredProcedure, spName, commandTimeout, dataSet, tableNames);
            }
        }

        /// <summary>
        ///     对于这个提供的Sql事务执行一个没有返回结果集合和没有参数的Sql命令。
        /// </summary>
        /// <param name="transaction">一个有效的Sql事务</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)。</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令。</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <param name="dataSet">一个包含由命令产生结果集合的dataset</param>
        /// <param name="tableNames">
        ///     这个数组用于创建一个允许DataTables通过用户定义名字(可能是实际的表名)来被table mapping参考。
        /// </param>
        public static void FillDataset(OracleTransaction transaction, CommandType commandType,
                                       string commandText, int commandTimeout,
                                       DataSet dataSet, string[] tableNames)
        {
            FillDataset(transaction, commandType, commandText, commandTimeout, dataSet, tableNames, null);
        }

        /// <summary>
        ///     对于指定的Sql事务使用提供的参数执行返回结果集合的Sql命令。
        /// </summary>
        /// <param name="transaction">一个有效的Sql事务</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)。</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <param name="dataSet">一个包含由命令产生结果集合的dataset</param>
        /// <param name="tableNames">
        ///     这个数组用于创建一个允许DataTables通过用户定义名字(可能是实际的表名)来被table mapping参考。
        /// </param>
        /// <param name="commandParameters">用于执行命令的Sql数组参数</param>
        public static void FillDataset(OracleTransaction transaction, CommandType commandType,
                                       string commandText, int commandTimeout, DataSet dataSet, string[] tableNames,
                                       params OracleParameter[] commandParameters)
        {
            FillDataset(transaction.Connection, transaction, commandType, commandText, commandTimeout, dataSet,
                        tableNames, commandParameters);
        }

        /// <summary>
        ///     通过Sql命令(返回一个结果集合)来执行这个存储过程，
        ///     这个存储过程是为指定一个使用数据行列值作为存储过程参数值的连接字符串的Sql 事务服务的。
        ///     这个方法为了发现存储过程(每一个第一次被调用的存储过程)的参数，它将会查询数据库, 并且按照参数的顺序给参数赋值。
        /// </summary>
        /// <param name="transaction">一个有效的Sql事务</param>
        /// <param name="spName">存储过程名字</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <param name="dataSet">一个包含由命令产生结果集合的dataset</param>
        /// <param name="tableNames">
        ///     这个数组用于创建一个允许DataTables通过用户定义名字(可能是实际的表名)来被table mapping参考。
        /// </param>
        /// <param name="parameterValues">存储过程输入参数的值将赋给对象数组</param>
        public static void FillDataset(OracleTransaction transaction, string spName, int commandTimeout,
                                       DataSet dataSet, string[] tableNames,
                                       params object[] parameterValues)
        {
            if (transaction == null) throw new ArgumentNullException("transaction");
            if (transaction != null && transaction.Connection == null)
                throw new ArgumentException(
                    "The transaction was rollbacked or commited, please provide an open transaction.", "transaction");
            if (dataSet == null) throw new ArgumentNullException("dataSet");
            if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");

            // If we receive parameter values, we need to figure out where they go
            // 如果我们接受到参数的值，我们需要知道它们来自那里
            if ((parameterValues != null) && (parameterValues.Length > 0))
            {
                // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
                // 从存放着参数的缓存器中填充这个存储过程的参数

                OracleParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(transaction.Connection,
                                                                                                spName);

                // Assign the provided values to these parameters based on parameter order
                // 按参数顺序给这些参数赋值
                AssignParameterValues(commandParameters, parameterValues);

                // Call the overload that takes an array of OracleParameters
                // 调用接受Sql参数数组的overload
                FillDataset(transaction, CommandType.StoredProcedure, spName, commandTimeout, dataSet, tableNames,
                            commandParameters);
            }
            else
            {
                // Otherwise we can just call the SP without params
                // 否则，我们仅仅只能调用没有参数的SP
                FillDataset(transaction, CommandType.StoredProcedure, spName, commandTimeout, dataSet, tableNames);
            }
        }

        /// <summary>
        ///     helper这个方法是一个执行Sql命令(返回结果集合)针对指定的Sql事务和使用参数的Sql连接对象。
        /// </summary>
        /// <param name="connection">一个有效的Sql连接</param>
        /// <param name="transaction">一个有效的Sql事务</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <param name="dataSet">一个包含由命令产生结果集合的dataset</param>
        /// <param name="tableNames">
        ///     这个数组用于创建一个允许DataTables通过用户定义名字(可能是实际的表名)来被表图参考。
        /// </param>
        /// <param name="commandParameters">An array of SqlParamters used to execute the command</param>
        private static void FillDataset(OracleConnection connection, OracleTransaction transaction,
                                        CommandType commandType,
                                        string commandText, int commandTimeout, DataSet dataSet, string[] tableNames,
                                        params OracleParameter[] commandParameters)
        {
            if (connection == null) throw new ArgumentNullException("connection");
            if (dataSet == null) throw new ArgumentNullException("dataSet");

            // Create a command and prepare it for execution
            // 创建一个命令，以用它来执行
            var command = new OracleCommand();
            bool mustCloseConnection = false;
            PrepareCommand(command, connection, transaction, commandType, commandText, commandTimeout, commandParameters,
                           out mustCloseConnection);

            // Create the DataAdapter & DataSet
            // 创建DataAdapter & DataSet
            using (var dataAdapter = new OracleDataAdapter(command))
            {
                // Add the table mappings specified by the user
                // 增加一个用户指定的table mapping
                if (tableNames != null && tableNames.Length > 0)
                {
                    string tableName = "Table";
                    for (int index = 0; index < tableNames.Length; index++)
                    {
                        if (tableNames[index] == null || tableNames[index].Length == 0)
                            throw new ArgumentException(
                                "The tableNames parameter must contain a list of tables, a value was provided as null or empty string.",
                                "tableNames");
                        dataAdapter.TableMappings.Add(tableName, tableNames[index]);
                        tableName += (index + 1).ToString();
                    }
                }

                // Fill the DataSet using default values for DataTable names, etc
                // 使用默认的DataTable的名字，等来填充DataSet
                dataAdapter.Fill(dataSet);

                // Detach the OracleParameters from the command object, so they can be used again
                // 从命令对象中释放Sql参数，以便于它们可以再次被使用
                command.Parameters.Clear();
            }

            if (mustCloseConnection)
                connection.Close();
        }

        #endregion

        #region UpdateDataset

        /// <summary>
        ///     在DataSet每一行中分别执行inserted,updated,or deleted命令
        /// </summary>
        /// <param name="insertCommand">一个有效的transact-SQL声明或者一个向数据源插入新记录的存储过程</param>
        /// <param name="deleteCommand">一个有效的transact-SQL声明或者一个向数据源删除新记录的存储过程</param>
        /// <param name="updateCommand">一个有效的transact-SQL声明或者一个向数据源更新新记录的存储过程</param>
        /// <param name="dataSet">更新数据源的DataSet</param>
        /// <param name="tableName">更新数据源的表</param>
        public static void UpdateDataset(OracleCommand insertCommand, OracleCommand deleteCommand,
                                         OracleCommand updateCommand, DataSet dataSet, string tableName)
        {
            if (insertCommand == null) throw new ArgumentNullException("insertCommand");
            if (deleteCommand == null) throw new ArgumentNullException("deleteCommand");
            if (updateCommand == null) throw new ArgumentNullException("updateCommand");
            if (tableName == null || tableName.Length == 0) throw new ArgumentNullException("tableName");

            // Create a OracleDataAdapter, and dispose of it after we are done
            // 创建一个SqlDataAdapte, 我们用完它以后把它释放掉
            using (var dataAdapter = new OracleDataAdapter())
            {
                // Set the data adapter commands
                // 给data adapter 命令赋值
                dataAdapter.UpdateCommand = updateCommand;
                dataAdapter.InsertCommand = insertCommand;
                dataAdapter.DeleteCommand = deleteCommand;

                // Update the dataset changes in the data source
                // 更新dataset在数据源中的变化
                dataAdapter.Update(dataSet, tableName);

                // Commit all the changes made to the DataSet
                // 提交所有的在DataSet中的变化
                dataSet.AcceptChanges();
            }
        }

        #endregion

        #region CreateCommand

        /// <summary>
        ///     通过允许提供存储过程和其任意参数来简化Sql命令的创建。
        /// </summary>
        /// <param name="connection">一个有效的Sql连接对象</param>
        /// <param name="spName">一个存储过程的名字</param>
        /// <param name="sourceColumns">一个被赋值的存放着存储过程参数的字符串数组</param>
        public static OracleCommand CreateCommand(OracleConnection connection, string spName,
                                                  params string[] sourceColumns)
        {
            if (connection == null) throw new ArgumentNullException("connection");
            if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");

            // Create a OracleCommand
            //创建一个Sql命令
            var cmd = new OracleCommand(spName, connection);
            cmd.CommandType = CommandType.StoredProcedure;

            // If we receive parameter values, we need to figure out where they go
            // 如果我们接受到参数值，我们需要知道这些参数来自那里
            if ((sourceColumns != null) && (sourceColumns.Length > 0))
            {
                // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
                // 从存放着参数的缓存器中提取参数给这个存储过程
                OracleParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connection, spName);

                // Assign the provided source columns to these parameters based on parameter order
                // 按参数的顺序给source columns赋值
                for (int index = 0; index < sourceColumns.Length; index++)
                    commandParameters[index].SourceColumn = sourceColumns[index];

                // Attach the discovered parameters to the OracleCommand object
                // 匹配这个发现的相对于Sql命令对象的参数
                AttachParameters(cmd, commandParameters);
            }

            return cmd;
        }

        #endregion

        #region ExecuteNonQueryTypedParams

        /// <summary>
        ///     通过Sql命令(返回一个结果集合)来执行这个存储过程，
        ///     这个存储过程是为指定一个使用数据行列值作为存储过程参数值的连接字符串的数据库服务的。
        ///     这个方法为了发现存储过程(每一个第一次被调用的存储过程)的参数，它将会查询数据库, 并且按照参数的顺序给参数赋值。
        /// </summary>
        /// <param name="connectionString">一个有效的Sql连接字符串</param>
        /// <param name="spName">存储过程的名字</param>
        /// <param name="dataRow">存储着存储过程参数值的数据行</param>
        /// <returns>一个受命令影响的整型的行数</returns>
        public static int ExecuteNonQueryTypedParams(String connectionString, String spName, DataRow dataRow)
        {
            if (connectionString == null || connectionString.Length == 0)
                throw new ArgumentNullException("connectionString");
            if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");

            // If the row has values, the store procedure parameters must be initialized
            // 如果这个行已有了值，存储过程参数必需要初始化

            if (dataRow != null && dataRow.ItemArray.Length > 0)
            {
                // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
                // 从存放着参数的缓存器中填充这个存储过程的参数
                OracleParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connectionString, spName);

                // Set the parameters values
                // 设置参数的值
                AssignParameterValues(commandParameters, dataRow);

                return OracleHelper.ExecuteNonQuery(connectionString, CommandType.StoredProcedure, spName,
                                                 commandParameters);
            }
            else
            {
                return OracleHelper.ExecuteNonQuery(connectionString, CommandType.StoredProcedure, spName);
            }
        }

        /// <summary>
        ///     通过Sql命令(返回一个结果集合)来执行这个存储过程，
        ///     这个存储过程是为指定一个使用数据行列值作为存储过程参数值的Sql连接对象服务的。
        ///     这个方法为了发现存储过程(每一个第一次被调用的存储过程)的参数，它将会查询数据库, 并且按照参数的顺序给参数赋值。
        /// </summary>
        /// <param name="connection">一个有效的Sql连接对象</param>
        /// <param name="spName">存储过程的名字</param>
        /// <param name="dataRow">存储着存储过程参数值的数据行</param>
        /// <return>一个受命令影响的整型的行数</return>
        public static int ExecuteNonQueryTypedParams(OracleConnection connection, String spName, DataRow dataRow)
        {
            if (connection == null) throw new ArgumentNullException("connection");
            if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");

            // If the row has values, the store procedure parameters must be initialized
            // 如果这个行已有了值，存储过程参数必需要初始化
            if (dataRow != null && dataRow.ItemArray.Length > 0)
            {
                // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
                // 从存放着参数的缓存器中填充这个存储过程的参数
                OracleParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connection, spName);

                // Set the parameters values
                // 设置参数的值
                AssignParameterValues(commandParameters, dataRow);

                return OracleHelper.ExecuteNonQuery(connection, CommandType.StoredProcedure, spName, commandParameters);
            }
            else
            {
                return OracleHelper.ExecuteNonQuery(connection, CommandType.StoredProcedure, spName);
            }
        }

        /// <summary>
        ///     通过Sql命令(返回一个结果集合)来执行这个存储过程，
        ///     这个存储过程是为指定一个使用数据行列值作为存储过程参数值的连接字符串的Sql事务服务的。
        ///     这个方法为了发现存储过程(每一个第一次被调用的存储过程)的参数，它将会查询数据库, 并且按照参数的顺序给参数赋值。
        /// </summary>
        /// <param name="transaction">一个有效的Sql事务</param>
        /// <param name="spName">存储过程的名字</param>
        /// <param name="dataRow">存储着存储过程参数值的数据行</param>
        /// <returns>一个受命令影响的整型的行数</returns>
        public static int ExecuteNonQueryTypedParams(OracleTransaction transaction, String spName, DataRow dataRow)
        {
            if (transaction == null) throw new ArgumentNullException("transaction");
            if (transaction != null && transaction.Connection == null)
                throw new ArgumentException(
                    "The transaction was rollbacked or commited, please provide an open transaction.", "transaction");
            if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");

            // If the row has values, the store procedure parameters must be initialized
            // 如果这个行已有了值，存储过程参数必需要初始化

            if (dataRow != null && dataRow.ItemArray.Length > 0)
            {
                // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
                // 从存放着参数的缓存器中填充这个存储过程的参数
                OracleParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(transaction.Connection,
                                                                                                spName);

                // Set the parameters values
                // 设置参数的值
                AssignParameterValues(commandParameters, dataRow);

                return OracleHelper.ExecuteNonQuery(transaction, CommandType.StoredProcedure, spName, commandParameters);
            }
            else
            {
                return OracleHelper.ExecuteNonQuery(transaction, CommandType.StoredProcedure, spName);
            }
        }

        /// <summary>
        ///     通过Sql命令(返回一个结果集合)来执行这个存储过程，
        ///     这个存储过程是为指定一个使用数据行列值作为存储过程参数值的连接字符串的数据库服务的。
        ///     这个方法为了发现存储过程(每一个第一次被调用的存储过程)的参数，它将会查询数据库, 并且按照参数的顺序给参数赋值。
        /// </summary>
        /// <param name="connectionString">一个有效的Sql连接字符串</param>
        /// <param name="spName">存储过程的名字</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <param name="dataRow">存储着存储过程参数值的数据行</param>
        /// <returns>一个受命令影响的整型的行数</returns>
        public static int ExecuteNonQueryTypedParams(String connectionString, String spName, int commandTimeout,
                                                     DataRow dataRow)
        {
            if (connectionString == null || connectionString.Length == 0)
                throw new ArgumentNullException("connectionString");
            if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");

            // If the row has values, the store procedure parameters must be initialized
            // 如果这个行已有了值，存储过程参数必需要初始化

            if (dataRow != null && dataRow.ItemArray.Length > 0)
            {
                // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
                // 从存放着参数的缓存器中填充这个存储过程的参数
                OracleParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connectionString, spName);

                // Set the parameters values
                // 设置参数的值
                AssignParameterValues(commandParameters, dataRow);

                return OracleHelper.ExecuteNonQuery(connectionString, CommandType.StoredProcedure, spName, commandTimeout,
                                                 commandParameters);
            }
            else
            {
                return OracleHelper.ExecuteNonQuery(connectionString, CommandType.StoredProcedure, spName, commandTimeout);
            }
        }

        /// <summary>
        ///     通过Sql命令(返回一个结果集合)来执行这个存储过程，
        ///     这个存储过程是为指定一个使用数据行列值作为存储过程参数值的Sql连接对象服务的。
        ///     这个方法为了发现存储过程(每一个第一次被调用的存储过程)的参数，它将会查询数据库, 并且按照参数的顺序给参数赋值。
        /// </summary>
        /// <param name="connection">一个有效的Sql连接对象</param>
        /// <param name="spName">存储过程的名字</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <param name="dataRow">存储着存储过程参数值的数据行</param>
        /// <return>一个受命令影响的整型的行数</return>
        public static int ExecuteNonQueryTypedParams(OracleConnection connection, String spName, int commandTimeout,
                                                     DataRow dataRow)
        {
            if (connection == null) throw new ArgumentNullException("connection");
            if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");

            // If the row has values, the store procedure parameters must be initialized
            // 如果这个行已有了值，存储过程参数必需要初始化
            if (dataRow != null && dataRow.ItemArray.Length > 0)
            {
                // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
                // 从存放着参数的缓存器中填充这个存储过程的参数
                OracleParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connection, spName);

                // Set the parameters values
                // 设置参数的值
                AssignParameterValues(commandParameters, dataRow);

                return OracleHelper.ExecuteNonQuery(connection, CommandType.StoredProcedure, spName, commandTimeout,
                                                 commandParameters);
            }
            else
            {
                return OracleHelper.ExecuteNonQuery(connection, CommandType.StoredProcedure, spName, commandTimeout);
            }
        }

        /// <summary>
        ///     通过Sql命令(返回一个结果集合)来执行这个存储过程，
        ///     这个存储过程是为指定一个使用数据行列值作为存储过程参数值的连接字符串的Sql事务服务的。
        ///     这个方法为了发现存储过程(每一个第一次被调用的存储过程)的参数，它将会查询数据库, 并且按照参数的顺序给参数赋值。
        /// </summary>
        /// <param name="transaction">一个有效的Sql事务</param>
        /// <param name="spName">存储过程的名字</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <param name="dataRow">存储着存储过程参数值的数据行</param>
        /// <returns>一个受命令影响的整型的行数</returns>
        public static int ExecuteNonQueryTypedParams(OracleTransaction transaction, String spName, int commandTimeout,
                                                     DataRow dataRow)
        {
            if (transaction == null) throw new ArgumentNullException("transaction");
            if (transaction != null && transaction.Connection == null)
                throw new ArgumentException(
                    "The transaction was rollbacked or commited, please provide an open transaction.", "transaction");
            if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");

            // If the row has values, the store procedure parameters must be initialized
            // 如果这个行已有了值，存储过程参数必需要初始化

            if (dataRow != null && dataRow.ItemArray.Length > 0)
            {
                // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
                // 从存放着参数的缓存器中填充这个存储过程的参数
                OracleParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(transaction.Connection,
                                                                                                spName);

                // Set the parameters values
                // 设置参数的值
                AssignParameterValues(commandParameters, dataRow);

                return OracleHelper.ExecuteNonQuery(transaction, CommandType.StoredProcedure, spName, commandTimeout,
                                                 commandParameters);
            }
            else
            {
                return OracleHelper.ExecuteNonQuery(transaction, CommandType.StoredProcedure, spName, commandTimeout);
            }
        }

        #endregion

        #region ExecuteDatasetTypedParams

        /// <summary>
        ///     通过Sql命令(返回一个结果集合)来执行这个存储过程，
        ///     这个存储过程是为指定一个使用数据行列值作为存储过程参数值的连接字符串的数据库服务的。
        ///     这个方法为了发现存储过程(每一个第一次被调用的存储过程)的参数，它将会查询数据库, 并且按照参数的顺序给参数赋值。
        /// </summary>
        /// <param name="connectionString">一个有效的Sql连接对象</param>
        /// <param name="spName">存储过程的名字</param>
        /// <param name="dataRow">存储着存储过程参数值的数据行</param>
        /// <returns>一个包含由命令产生结果集合的dataset</returns>
        public static DataSet ExecuteDatasetTypedParams(string connectionString, String spName, DataRow dataRow)
        {
            if (connectionString == null || connectionString.Length == 0)
                throw new ArgumentNullException("connectionString");
            if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");

            //If the row has values, the store procedure parameters must be initialized
            // 如果这个行已有了值，存储过程参数必需要初始化
            if (dataRow != null && dataRow.ItemArray.Length > 0)
            {
                // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
                // 从存放着参数的缓存器中填充这个存储过程的参数
                OracleParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connectionString, spName);

                // Set the parameters values
                // 设置参数的值
                AssignParameterValues(commandParameters, dataRow);

                return OracleHelper.ExecuteDataset(connectionString, CommandType.StoredProcedure, spName, commandParameters);
            }
            else
            {
                return OracleHelper.ExecuteDataset(connectionString, CommandType.StoredProcedure, spName);
            }
        }

        /// <summary>
        ///     通过Sql命令(返回一个结果集合)来执行这个存储过程，
        ///     这个存储过程是为指定一个使用数据行列值作为存储过程参数值的连接字符串的Sql连接对象服务的。
        ///     这个方法为了发现存储过程(每一个第一次被调用的存储过程)的参数，它将会查询数据库, 并且按照参数的顺序给参数赋值。
        /// </summary>
        /// <param name="connection">一个有效的Sql连接对象</param>
        /// <param name="spName">存储过程的名字</param>
        /// <param name="dataRow">存储着存储过程参数值的数据行</param>
        /// <return>一个包含由命令产生结果集合的dataset</return>
        public static DataSet ExecuteDatasetTypedParams(OracleConnection connection, String spName, DataRow dataRow)
        {
            if (connection == null) throw new ArgumentNullException("connection");
            if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");

            // If the row has values, the store procedure parameters must be initialized
            // 如果这个行已有了值，存储过程参数必需要初始化
            if (dataRow != null && dataRow.ItemArray.Length > 0)
            {
                // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
                // 从存放着参数的缓存器中填充这个存储过程的参数
                OracleParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connection, spName);

                // Set the parameters values
                // 设置参数的值
                AssignParameterValues(commandParameters, dataRow);

                return OracleHelper.ExecuteDataset(connection, CommandType.StoredProcedure, spName, commandParameters);
            }
            else
            {
                return OracleHelper.ExecuteDataset(connection, CommandType.StoredProcedure, spName);
            }
        }

        /// <summary>
        ///     通过Sql命令(返回一个结果集合)来执行这个存储过程，
        ///     这个存储过程是为指定一个使用数据行列值作为存储过程参数值的连接字符串的Sql事务服务的。
        ///     这个方法为了发现存储过程(每一个第一次被调用的存储过程)的参数，它将会查询数据库, 并且按照参数的顺序给参数赋值。
        /// </summary>
        /// <param name="transaction">一个有效的Sql连接字符串</param>
        /// <param name="spName">存储过程的名字</param>
        /// <param name="dataRow">存储着存储过程参数值的数据行</param>
        /// <returns>一个包含由命令产生结果集合的dataset</returns>
        public static DataSet ExecuteDatasetTypedParams(OracleTransaction transaction, String spName, DataRow dataRow)
        {
            if (transaction == null) throw new ArgumentNullException("transaction");
            if (transaction != null && transaction.Connection == null)
                throw new ArgumentException(
                    "The transaction was rollbacked or commited, please provide an open transaction.", "transaction");
            if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");

            // If the row has values, the store procedure parameters must be initialized
            // 如果这个行已有了值，存储过程参数必需要初始化
            if (dataRow != null && dataRow.ItemArray.Length > 0)
            {
                // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
                // 从存放着参数的缓存器中填充这个存储过程的参数
                OracleParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(transaction.Connection,
                                                                                                spName);

                // Set the parameters values
                // 设置参数的值
                AssignParameterValues(commandParameters, dataRow);

                return OracleHelper.ExecuteDataset(transaction, CommandType.StoredProcedure, spName, commandParameters);
            }
            else
            {
                return OracleHelper.ExecuteDataset(transaction, CommandType.StoredProcedure, spName);
            }
        }

        /// <summary>
        ///     通过Sql命令(返回一个结果集合)来执行这个存储过程，
        ///     这个存储过程是为指定一个使用数据行列值作为存储过程参数值的连接字符串的数据库服务的。
        ///     这个方法为了发现存储过程(每一个第一次被调用的存储过程)的参数，它将会查询数据库, 并且按照参数的顺序给参数赋值。
        /// </summary>
        /// <param name="connectionString">一个有效的Sql连接对象</param>
        /// <param name="spName">存储过程的名字</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <param name="dataRow">存储着存储过程参数值的数据行</param>
        /// <returns>一个包含由命令产生结果集合的dataset</returns>
        public static DataSet ExecuteDatasetTypedParams(string connectionString, String spName, int commandTimeout,
                                                        DataRow dataRow)
        {
            if (connectionString == null || connectionString.Length == 0)
                throw new ArgumentNullException("connectionString");
            if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");

            //If the row has values, the store procedure parameters must be initialized
            // 如果这个行已有了值，存储过程参数必需要初始化
            if (dataRow != null && dataRow.ItemArray.Length > 0)
            {
                // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
                // 从存放着参数的缓存器中填充这个存储过程的参数
                OracleParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connectionString, spName);

                // Set the parameters values
                // 设置参数的值
                AssignParameterValues(commandParameters, dataRow);

                return OracleHelper.ExecuteDataset(connectionString, CommandType.StoredProcedure, spName, commandTimeout,
                                                commandParameters);
            }
            else
            {
                return OracleHelper.ExecuteDataset(connectionString, CommandType.StoredProcedure, spName, commandTimeout);
            }
        }

        /// <summary>
        ///     通过Sql命令(返回一个结果集合)来执行这个存储过程，
        ///     这个存储过程是为指定一个使用数据行列值作为存储过程参数值的连接字符串的Sql连接对象服务的。
        ///     这个方法为了发现存储过程(每一个第一次被调用的存储过程)的参数，它将会查询数据库, 并且按照参数的顺序给参数赋值。
        /// </summary>
        /// <param name="connection">一个有效的Sql连接对象</param>
        /// <param name="spName">存储过程的名字</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <param name="dataRow">存储着存储过程参数值的数据行</param>
        /// <return>一个包含由命令产生结果集合的dataset</return>
        public static DataSet ExecuteDatasetTypedParams(OracleConnection connection, String spName, int commandTimeout,
                                                        DataRow dataRow)
        {
            if (connection == null) throw new ArgumentNullException("connection");
            if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");

            // If the row has values, the store procedure parameters must be initialized
            // 如果这个行已有了值，存储过程参数必需要初始化
            if (dataRow != null && dataRow.ItemArray.Length > 0)
            {
                // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
                // 从存放着参数的缓存器中填充这个存储过程的参数
                OracleParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connection, spName);

                // Set the parameters values
                // 设置参数的值
                AssignParameterValues(commandParameters, dataRow);

                return OracleHelper.ExecuteDataset(connection, CommandType.StoredProcedure, spName, commandTimeout,
                                                commandParameters);
            }
            else
            {
                return OracleHelper.ExecuteDataset(connection, CommandType.StoredProcedure, spName, commandTimeout);
            }
        }

        /// <summary>
        ///     通过Sql命令(返回一个结果集合)来执行这个存储过程，
        ///     这个存储过程是为指定一个使用数据行列值作为存储过程参数值的连接字符串的Sql事务服务的。
        ///     这个方法为了发现存储过程(每一个第一次被调用的存储过程)的参数，它将会查询数据库, 并且按照参数的顺序给参数赋值。
        /// </summary>
        /// <param name="transaction">一个有效的Sql连接字符串</param>
        /// <param name="spName">存储过程的名字</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <param name="dataRow">存储着存储过程参数值的数据行</param>
        /// <returns>一个包含由命令产生结果集合的dataset</returns>
        public static DataSet ExecuteDatasetTypedParams(OracleTransaction transaction, String spName, int commandTimeout,
                                                        DataRow dataRow)
        {
            if (transaction == null) throw new ArgumentNullException("transaction");
            if (transaction != null && transaction.Connection == null)
                throw new ArgumentException(
                    "The transaction was rollbacked or commited, please provide an open transaction.", "transaction");
            if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");

            // If the row has values, the store procedure parameters must be initialized
            // 如果这个行已有了值，存储过程参数必需要初始化
            if (dataRow != null && dataRow.ItemArray.Length > 0)
            {
                // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
                // 从存放着参数的缓存器中填充这个存储过程的参数
                OracleParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(transaction.Connection,
                                                                                                spName);

                // Set the parameters values
                // 设置参数的值
                AssignParameterValues(commandParameters, dataRow);

                return OracleHelper.ExecuteDataset(transaction, CommandType.StoredProcedure, spName, commandTimeout,
                                                commandParameters);
            }
            else
            {
                return OracleHelper.ExecuteDataset(transaction, CommandType.StoredProcedure, spName, commandTimeout);
            }
        }

        #endregion

        #region ExecuteReaderTypedParams

        /// <summary>
        ///     通过Sql命令(返回一个1x1结果集合)来执行这个存储过程，
        ///     这个存储过程是为指定一个使用数据行列值作为存储过程参数值的连接字符串的数据库服务的。
        ///     这个方法将会查询发现存储过程(每一个第一次被调用的存储过程)参数的数据库, 并且按照参数的顺序给参数赋值。
        /// </summary>
        /// <param name="connectionString">一个有效的Sql连接字符串</param>
        /// <param name="spName">存储过程的名字</param>
        /// <param name="dataRow">存储着存储过程参数值的数据行</param>
        /// <returns>一个包含由命令产生结果集合的OracleDataReader</returns>
        public static OracleDataReader ExecuteReaderTypedParams(String connectionString, String spName, DataRow dataRow)
        {
            if (connectionString == null || connectionString.Length == 0)
                throw new ArgumentNullException("connectionString");
            if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");

            // If the row has values, the store procedure parameters must be initialized
            // 如果这个行已有了值，存储过程参数必需要初始化
            if (dataRow != null && dataRow.ItemArray.Length > 0)
            {
                // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
                // 从存放着参数的缓存器中填充这个存储过程的参数

                OracleParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connectionString, spName);

                // Set the parameters values
                // 设置参数的值

                AssignParameterValues(commandParameters, dataRow);

                return OracleHelper.ExecuteReader(connectionString, CommandType.StoredProcedure, spName, commandParameters);
            }
            else
            {
                return OracleHelper.ExecuteReader(connectionString, CommandType.StoredProcedure, spName);
            }
        }

        /// <summary>
        ///     通过Sql命令(返回一个结果集合)来执行这个存储过程，
        ///     这个存储过程是为指定一个使用数据行列值作为存储过程参数值的Sql连接对象服务的。
        ///     这个方法为了要发现存储过程(每一个第一次被调用的存储过程)的参数，它将会查询数据库, 并且按照参数的顺序给参数赋值。
        /// </summary>
        /// <param name="connection">一个有效的Sql连接对象</param>
        /// <param name="spName">存储过程的名字</param>
        /// <param name="dataRow">存储着存储过程参数值的数据行</param>
        /// <returns>一个包含由命令产生结果集合的OracleDataReader</returns>
        public static OracleDataReader ExecuteReaderTypedParams(OracleConnection connection, String spName,
                                                                DataRow dataRow)
        {
            if (connection == null) throw new ArgumentNullException("connection");
            if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");

            // If the row has values, the store procedure parameters must be initialized
            // 如果这个行已有了值，存储过程参数必需要初始化

            if (dataRow != null && dataRow.ItemArray.Length > 0)
            {
                // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
                // 从存放着参数的缓存器中填充这个存储过程的参数
                OracleParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connection, spName);

                // Set the parameters values
                // 设置参数的值

                AssignParameterValues(commandParameters, dataRow);

                return OracleHelper.ExecuteReader(connection, CommandType.StoredProcedure, spName, commandParameters);
            }
            else
            {
                return OracleHelper.ExecuteReader(connection, CommandType.StoredProcedure, spName);
            }
        }

        /// <summary>
        ///     通过Sql命令(返回一个结果集合)来执行这个存储过程，
        ///     这个存储过程是为指定一个使用数据行列值作为存储过程参数值的Sql事务服务的。
        ///     这个方法为了要发现存储过程(每一个第一次被调用的存储过程)的参数，它将会查询数据库, 并且按照参数的顺序给参数赋值。
        /// </summary>
        /// <param name="transaction">一个有效的Sql事务</param>
        /// <param name="spName">存储过程的名字</param>
        /// <param name="dataRow">存储着存储过程参数值的数据行</param>
        /// <returns>一个包含由命令产生结果集合的OracleDataReader</returns>
        public static OracleDataReader ExecuteReaderTypedParams(OracleTransaction transaction, String spName,
                                                                DataRow dataRow)
        {
            if (transaction == null) throw new ArgumentNullException("transaction");
            if (transaction != null && transaction.Connection == null)
                throw new ArgumentException(
                    "The transaction was rollbacked or commited, please provide an open transaction.", "transaction");
            if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");

            // If the row has values, the store procedure parameters must be initialized
            // 如果这个行已有了值，存储过程参数必需要初始化
            if (dataRow != null && dataRow.ItemArray.Length > 0)
            {
                // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
                // 从存放着参数的缓存器中填充这个存储过程的参数
                OracleParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(transaction.Connection,
                                                                                                spName);

                // Set the parameters values
                // 设置参数的值
                AssignParameterValues(commandParameters, dataRow);

                return OracleHelper.ExecuteReader(transaction, CommandType.StoredProcedure, spName, commandParameters);
            }
            else
            {
                return OracleHelper.ExecuteReader(transaction, CommandType.StoredProcedure, spName);
            }
        }

        /// <summary>
        ///     通过Sql命令(返回一个1x1结果集合)来执行这个存储过程，
        ///     这个存储过程是为指定一个使用数据行列值作为存储过程参数值的连接字符串的数据库服务的。
        ///     这个方法将会查询发现存储过程(每一个第一次被调用的存储过程)参数的数据库, 并且按照参数的顺序给参数赋值。
        /// </summary>
        /// <param name="connectionString">一个有效的Sql连接字符串</param>
        /// <param name="spName">存储过程的名字</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <param name="dataRow">存储着存储过程参数值的数据行</param>
        /// <returns>一个包含由命令产生结果集合的OracleDataReader</returns>
        public static OracleDataReader ExecuteReaderTypedParams(String connectionString, String spName,
                                                                int commandTimeout, DataRow dataRow)
        {
            if (connectionString == null || connectionString.Length == 0)
                throw new ArgumentNullException("connectionString");
            if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");

            // If the row has values, the store procedure parameters must be initialized
            // 如果这个行已有了值，存储过程参数必需要初始化
            if (dataRow != null && dataRow.ItemArray.Length > 0)
            {
                // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
                // 从存放着参数的缓存器中填充这个存储过程的参数

                OracleParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connectionString, spName);

                // Set the parameters values
                // 设置参数的值

                AssignParameterValues(commandParameters, dataRow);

                return OracleHelper.ExecuteReader(connectionString, CommandType.StoredProcedure, spName, commandTimeout,
                                               commandParameters);
            }
            else
            {
                return OracleHelper.ExecuteReader(connectionString, CommandType.StoredProcedure, spName, commandTimeout);
            }
        }

        /// <summary>
        ///     通过Sql命令(返回一个结果集合)来执行这个存储过程，
        ///     这个存储过程是为指定一个使用数据行列值作为存储过程参数值的Sql连接对象服务的。
        ///     这个方法为了要发现存储过程(每一个第一次被调用的存储过程)的参数，它将会查询数据库, 并且按照参数的顺序给参数赋值。
        /// </summary>
        /// <param name="connection">一个有效的Sql连接对象</param>
        /// <param name="spName">存储过程的名字</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <param name="dataRow">存储着存储过程参数值的数据行</param>
        /// <returns>一个包含由命令产生结果集合的OracleDataReader</returns>
        public static OracleDataReader ExecuteReaderTypedParams(OracleConnection connection, String spName,
                                                                int commandTimeout, DataRow dataRow)
        {
            if (connection == null) throw new ArgumentNullException("connection");
            if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");

            // If the row has values, the store procedure parameters must be initialized
            // 如果这个行已有了值，存储过程参数必需要初始化

            if (dataRow != null && dataRow.ItemArray.Length > 0)
            {
                // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
                // 从存放着参数的缓存器中填充这个存储过程的参数
                OracleParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connection, spName);

                // Set the parameters values
                // 设置参数的值

                AssignParameterValues(commandParameters, dataRow);

                return OracleHelper.ExecuteReader(connection, CommandType.StoredProcedure, spName, commandTimeout,
                                               commandParameters);
            }
            else
            {
                return OracleHelper.ExecuteReader(connection, CommandType.StoredProcedure, spName, commandTimeout);
            }
        }

        /// <summary>
        ///     通过Sql命令(返回一个结果集合)来执行这个存储过程，
        ///     这个存储过程是为指定一个使用数据行列值作为存储过程参数值的Sql事务服务的。
        ///     这个方法为了要发现存储过程(每一个第一次被调用的存储过程)的参数，它将会查询数据库, 并且按照参数的顺序给参数赋值。
        /// </summary>
        /// <param name="transaction">一个有效的Sql事务</param>
        /// <param name="spName">存储过程的名字</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <param name="dataRow">存储着存储过程参数值的数据行</param>
        /// <returns>一个包含由命令产生结果集合的OracleDataReader</returns>
        public static OracleDataReader ExecuteReaderTypedParams(OracleTransaction transaction, String spName,
                                                                int commandTimeout, DataRow dataRow)
        {
            if (transaction == null) throw new ArgumentNullException("transaction");
            if (transaction != null && transaction.Connection == null)
                throw new ArgumentException(
                    "The transaction was rollbacked or commited, please provide an open transaction.", "transaction");
            if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");

            // If the row has values, the store procedure parameters must be initialized
            // 如果这个行已有了值，存储过程参数必需要初始化
            if (dataRow != null && dataRow.ItemArray.Length > 0)
            {
                // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
                // 从存放着参数的缓存器中填充这个存储过程的参数
                OracleParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(transaction.Connection,
                                                                                                spName);

                // Set the parameters values
                // 设置参数的值
                AssignParameterValues(commandParameters, dataRow);

                return OracleHelper.ExecuteReader(transaction, CommandType.StoredProcedure, spName, commandTimeout,
                                               commandParameters);
            }
            else
            {
                return OracleHelper.ExecuteReader(transaction, CommandType.StoredProcedure, spName, commandTimeout);
            }
        }

        #endregion

        #region ExecuteScalarTypedParams

        /// <summary>
        ///     通过Sql命令(返回一个1x1结果集合)来执行这个存储过程，
        ///     这个存储过程是为指定一个使用数据行列值作为存储过程参数值的连接字符串的数据库服务的。
        ///     这个方法将会查询发现存储过程(每一个第一次被调用的存储过程)参数的数据库, 并且按照参数的顺序给参数赋值。
        /// </summary>
        /// <param name="connectionString">一个有效的Sql连接字符串</param>
        /// <param name="spName">存储过程的名字</param>
        /// <param name="dataRow">存储着存储过程参数值的数据行</param>
        /// <returns>一个包含由命令产生1x1结果集合的对象</returns>
        public static object ExecuteScalarTypedParams(String connectionString, String spName, DataRow dataRow)
        {
            if (connectionString == null || connectionString.Length == 0)
                throw new ArgumentNullException("connectionString");
            if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");

            // If the row has values, the store procedure parameters must be initialized
            // 如果这个行已有了值，存储过程参数必需要初始化
            if (dataRow != null && dataRow.ItemArray.Length > 0)
            {
                // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
                // 从存放着参数的缓存器中填充这个存储过程的参数
                OracleParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connectionString, spName);

                // Set the parameters values
                // 设置参数的值
                AssignParameterValues(commandParameters, dataRow);

                return OracleHelper.ExecuteScalar(connectionString, CommandType.StoredProcedure, spName, commandParameters);
            }
            else
            {
                return OracleHelper.ExecuteScalar(connectionString, CommandType.StoredProcedure, spName);
            }
        }

        /// <summary>
        ///     以数据行列的值作为存储过程参数的值，用Sql命令(返回1x1结果集合)执行一个存储过程，这个存储过程是为指定的Sql事务服务的。
        ///     这个方法将会查询发现存储过程(每一个第一次被调用的存储过程)参数的数据库, 并且按照参数的顺序给参数赋值。
        /// </summary>
        /// <param name="connection">一个有效的Sql连接对象</param>
        /// <param name="spName">存储过程的名字</param>
        /// <param name="dataRow">存储着存储过程参数值的数据行</param>
        /// <returns>一个包含由命令产生1x1结果集合的对象</returns>
        public static object ExecuteScalarTypedParams(OracleConnection connection, String spName, DataRow dataRow)
        {
            if (connection == null) throw new ArgumentNullException("connection");
            if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");

            // If the row has values, the store procedure parameters must be initialized
            // 如果这个行已有了值，存储过程参数必需要初始化
            if (dataRow != null && dataRow.ItemArray.Length > 0)
            {
                // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
                // 从存放着参数的缓存器中填充这个存储过程的参数
                OracleParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connection, spName);

                // Set the parameters values
                // 设置参数的值
                AssignParameterValues(commandParameters, dataRow);

                return OracleHelper.ExecuteScalar(connection, CommandType.StoredProcedure, spName, commandParameters);
            }
            else
            {
                return OracleHelper.ExecuteScalar(connection, CommandType.StoredProcedure, spName);
            }
        }

        /// <summary>
        ///     以数据行列的值作为存储过程参数的值，用Sql命令(返回1x1结果集合)执行一个存储过程，这个存储过程是为指定的Sql事务服务的。
        ///     这个方法将会查询发现存储过程(每一个第一次被调用的存储过程)参数的数据库, 并且按照参数的顺序给参数赋值。
        /// </summary>
        /// <param name="transaction">一个有效的Sql事务</param>
        /// <param name="spName">存储过程的名字</param>
        /// <param name="dataRow">存储着存储过程参数值的数据行</param>
        /// <returns>一个包含由命令产生1x1结果集合的XmlReader</returns>
        public static object ExecuteScalarTypedParams(OracleTransaction transaction, String spName, DataRow dataRow)
        {
            if (transaction == null) throw new ArgumentNullException("transaction");
            if (transaction != null && transaction.Connection == null)
                throw new ArgumentException(
                    "The transaction was rollbacked or commited, please provide an open transaction.", "transaction");
            if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");

            // If the row has values, the store procedure parameters must be initialized
            // 如果这个行已有了值，存储过程参数必需要初始化
            if (dataRow != null && dataRow.ItemArray.Length > 0)
            {
                // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
                // 从存放着参数的缓存器中填充这个存储过程的参数
                OracleParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(transaction.Connection,
                                                                                                spName);

                // Set the parameters values
                // 设置参数的值
                AssignParameterValues(commandParameters, dataRow);

                return OracleHelper.ExecuteScalar(transaction, CommandType.StoredProcedure, spName, commandParameters);
            }
            else
            {
                return OracleHelper.ExecuteScalar(transaction, CommandType.StoredProcedure, spName);
            }
        }

        /// <summary>
        ///     通过Sql命令(返回一个1x1结果集合)来执行这个存储过程，
        ///     这个存储过程是为指定一个使用数据行列值作为存储过程参数值的连接字符串的数据库服务的。
        ///     这个方法将会查询发现存储过程(每一个第一次被调用的存储过程)参数的数据库, 并且按照参数的顺序给参数赋值。
        /// </summary>
        /// <param name="connectionString">一个有效的Sql连接字符串</param>
        /// <param name="spName">存储过程的名字</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <param name="dataRow">存储着存储过程参数值的数据行</param>
        /// <returns>一个包含由命令产生1x1结果集合的对象</returns>
        public static object ExecuteScalarTypedParams(String connectionString, String spName, int commandTimeout,
                                                      DataRow dataRow)
        {
            if (connectionString == null || connectionString.Length == 0)
                throw new ArgumentNullException("connectionString");
            if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");

            // If the row has values, the store procedure parameters must be initialized
            // 如果这个行已有了值，存储过程参数必需要初始化
            if (dataRow != null && dataRow.ItemArray.Length > 0)
            {
                // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
                // 从存放着参数的缓存器中填充这个存储过程的参数
                OracleParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connectionString, spName);

                // Set the parameters values
                // 设置参数的值
                AssignParameterValues(commandParameters, dataRow);

                return OracleHelper.ExecuteScalar(connectionString, CommandType.StoredProcedure, spName, commandTimeout,
                                               commandParameters);
            }
            else
            {
                return OracleHelper.ExecuteScalar(connectionString, CommandType.StoredProcedure, spName, commandTimeout);
            }
        }

        /// <summary>
        ///     以数据行列的值作为存储过程参数的值，用Sql命令(返回1x1结果集合)执行一个存储过程，这个存储过程是为指定的Sql事务服务的。
        ///     这个方法将会查询发现存储过程(每一个第一次被调用的存储过程)参数的数据库, 并且按照参数的顺序给参数赋值。
        /// </summary>
        /// <param name="connection">一个有效的Sql连接对象</param>
        /// <param name="spName">存储过程的名字</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <param name="dataRow">存储着存储过程参数值的数据行</param>
        /// <returns>一个包含由命令产生1x1结果集合的对象</returns>
        public static object ExecuteScalarTypedParams(OracleConnection connection, String spName, int commandTimeout,
                                                      DataRow dataRow)
        {
            if (connection == null) throw new ArgumentNullException("connection");
            if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");

            // If the row has values, the store procedure parameters must be initialized
            // 如果这个行已有了值，存储过程参数必需要初始化
            if (dataRow != null && dataRow.ItemArray.Length > 0)
            {
                // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
                // 从存放着参数的缓存器中填充这个存储过程的参数
                OracleParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connection, spName);

                // Set the parameters values
                // 设置参数的值
                AssignParameterValues(commandParameters, dataRow);

                return OracleHelper.ExecuteScalar(connection, CommandType.StoredProcedure, spName, commandTimeout,
                                               commandParameters);
            }
            else
            {
                return OracleHelper.ExecuteScalar(connection, CommandType.StoredProcedure, spName, commandTimeout);
            }
        }

        /// <summary>
        ///     以数据行列的值作为存储过程参数的值，用Sql命令(返回1x1结果集合)执行一个存储过程，这个存储过程是为指定的Sql事务服务的。
        ///     这个方法将会查询发现存储过程(每一个第一次被调用的存储过程)参数的数据库, 并且按照参数的顺序给参数赋值。
        /// </summary>
        /// <param name="transaction">一个有效的Sql事务</param>
        /// <param name="spName">存储过程的名字</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <param name="dataRow">存储着存储过程参数值的数据行</param>
        /// <returns>一个包含由命令产生1x1结果集合的XmlReader</returns>
        public static object ExecuteScalarTypedParams(OracleTransaction transaction, String spName, int commandTimeout,
                                                      DataRow dataRow)
        {
            if (transaction == null) throw new ArgumentNullException("transaction");
            if (transaction != null && transaction.Connection == null)
                throw new ArgumentException(
                    "The transaction was rollbacked or commited, please provide an open transaction.", "transaction");
            if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");

            // If the row has values, the store procedure parameters must be initialized
            // 如果这个行已有了值，存储过程参数必需要初始化
            if (dataRow != null && dataRow.ItemArray.Length > 0)
            {
                // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
                // 从存放着参数的缓存器中填充这个存储过程的参数
                OracleParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(transaction.Connection,
                                                                                                spName);

                // Set the parameters values
                // 设置参数的值
                AssignParameterValues(commandParameters, dataRow);

                return OracleHelper.ExecuteScalar(transaction, CommandType.StoredProcedure, spName, commandTimeout,
                                               commandParameters);
            }
            else
            {
                return OracleHelper.ExecuteScalar(transaction, CommandType.StoredProcedure, spName, commandTimeout);
            }
        }

        #endregion

        #region ExecuteXmlReaderTypedParams

        ///  <summary>
        ///  以数据行列的值作为存储过程参数的值，用Sql命令(返回结果集)执行一个存储过程，这个存储过程是为指定的Sql连接服务的。
        ///  这个方法将会查询发现存储过程(每一个第一次被调用的存储过程)参数的数据库, 并且按照参数的顺序给参数赋值。
        ///  </summary>
        ///  <param name="connection">一个有效的Sql连接对象</param>
        ///  <param name="spName">存储过程的名字</param>
        ///  <param name="dataRow">存储着存储过程参数值的数据行</param>
        ///  <returns>一个包含由命令产生结果集合的XmlReader</returns>
        public static XmlReader ExecuteXmlReaderTypedParams(OracleConnection connection, String spName, DataRow dataRow)
        {
            if (connection == null) throw new ArgumentNullException("connection");
            if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");

            // If the row has values, the store procedure parameters must be initialized
            // 如果这个行已有了值，存储过程参数必需要初始化
            if (dataRow != null && dataRow.ItemArray.Length > 0)
            {
                // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
                // 从存放着参数的缓存器中填充这个存储过程的参数
                OracleParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connection, spName);

                // Set the parameters values
                // 设置参数的值
                AssignParameterValues(commandParameters, dataRow);

                return OracleHelper.ExecuteXmlReader(connection, CommandType.StoredProcedure, spName, commandParameters);
            }
            else
            {
                return OracleHelper.ExecuteXmlReader(connection, CommandType.StoredProcedure, spName);
            }
        }

        ///  <summary>
        ///  以数据行列的值作为存储过程参数的值，用Sql命令(返回结果集)执行一个存储过程，这个存储过程是为指定的Sql事务服务的。
        ///  这个方法将会查询发现存储过程(每一个第一次被调用的存储过程)参数的数据库, 并且按照参数的顺序给参数赋值。
        ///  </summary>
        ///  <param name="transaction">一个有效的Sql事务</param>
        ///  <param name="spName">存储过程的名字</param>
        ///  <param name="dataRow">存储着存储过程参数值的数据行</param>
        ///  <returns>一个包含由命令产生结果集合的XmlReader</returns>
        public static XmlReader ExecuteXmlReaderTypedParams(OracleTransaction transaction, String spName, DataRow dataRow)
        {
            if (transaction == null) throw new ArgumentNullException("transaction");
            if (transaction != null && transaction.Connection == null) throw new ArgumentException("The transaction was rollbacked or commited, please provide an open transaction.", "transaction");
            if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");

            // If the row has values, the store procedure parameters must be initialized
            // 如果这个行已有了值，存储过程参数必需要初始化
            if (dataRow != null && dataRow.ItemArray.Length > 0)
            {
                // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
                // 从存放着参数的缓存器中填充这个存储过程的参数
                OracleParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(transaction.Connection, spName);

                // Set the parameters values
                // 设置参数的值
                AssignParameterValues(commandParameters, dataRow);

                return OracleHelper.ExecuteXmlReader(transaction, CommandType.StoredProcedure, spName, commandParameters);
            }
            else
            {
                return OracleHelper.ExecuteXmlReader(transaction, CommandType.StoredProcedure, spName);
            }
        }

        ///  <summary>
        ///  以数据行列的值作为存储过程参数的值，用Sql命令(返回结果集)执行一个存储过程，这个存储过程是为指定的Sql连接服务的。
        ///  这个方法将会查询发现存储过程(每一个第一次被调用的存储过程)参数的数据库, 并且按照参数的顺序给参数赋值。
        ///  </summary>
        ///  <param name="connection">一个有效的Sql连接对象</param>
        ///  <param name="spName">存储过程的名字</param>
        ///  <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        ///  <param name="dataRow">存储着存储过程参数值的数据行</param>
        ///  <returns>一个包含由命令产生结果集合的XmlReader</returns>
        public static XmlReader ExecuteXmlReaderTypedParams(OracleConnection connection, String spName, int commandTimeout, DataRow dataRow)
        {
            if (connection == null) throw new ArgumentNullException("connection");
            if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");

            // If the row has values, the store procedure parameters must be initialized
            // 如果这个行已有了值，存储过程参数必需要初始化
            if (dataRow != null && dataRow.ItemArray.Length > 0)
            {
                // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
                // 从存放着参数的缓存器中填充这个存储过程的参数
                OracleParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(connection, spName);

                // Set the parameters values
                // 设置参数的值
                AssignParameterValues(commandParameters, dataRow);

                return OracleHelper.ExecuteXmlReader(connection, CommandType.StoredProcedure, spName, commandTimeout, commandParameters);
            }
            else
            {
                return OracleHelper.ExecuteXmlReader(connection, CommandType.StoredProcedure, spName, commandTimeout);
            }
        }

        ///  <summary>
        ///  以数据行列的值作为存储过程参数的值，用Sql命令(返回结果集)执行一个存储过程，这个存储过程是为指定的Sql事务服务的。
        ///  这个方法将会查询发现存储过程(每一个第一次被调用的存储过程)参数的数据库, 并且按照参数的顺序给参数赋值。
        ///  </summary>
        ///  <param name="transaction">一个有效的Sql事务</param>
        ///  <param name="spName">存储过程的名字</param>
        ///  <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        ///  <param name="dataRow">存储着存储过程参数值的数据行</param>
        ///  <returns>一个包含由命令产生结果集合的XmlReader</returns>
        public static XmlReader ExecuteXmlReaderTypedParams(OracleTransaction transaction, String spName, int commandTimeout, DataRow dataRow)
        {
            if (transaction == null) throw new ArgumentNullException("transaction");
            if (transaction != null && transaction.Connection == null) throw new ArgumentException("The transaction was rollbacked or commited, please provide an open transaction.", "transaction");
            if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");

            // If the row has values, the store procedure parameters must be initialized
            // 如果这个行已有了值，存储过程参数必需要初始化
            if (dataRow != null && dataRow.ItemArray.Length > 0)
            {
                // Pull the parameters for this stored procedure from the parameter cache (or discover them & populate the cache)
                // 从存放着参数的缓存器中填充这个存储过程的参数
                OracleParameter[] commandParameters = SqlHelperParameterCache.GetSpParameterSet(transaction.Connection, spName);

                // Set the parameters values
                // 设置参数的值
                AssignParameterValues(commandParameters, dataRow);

                return OracleHelper.ExecuteXmlReader(transaction, CommandType.StoredProcedure, spName, commandTimeout, commandParameters);
            }
            else
            {
                return OracleHelper.ExecuteXmlReader(transaction, CommandType.StoredProcedure, spName, commandTimeout);
            }
        }


        /// <summary>
        ///     通过Sql命令(返回一个结果集合)来执行这个存储过程，
        ///     这个存储过程是为指定一个使用数据行列值作为存储过程参数值的连接字符串的Sql连接服务的。
        ///     这个方法为了发现存储过程(每一个第一次被调用的存储过程)的参数，它将会查询数据库, 并且按照参数的顺序给参数赋值。
        /// </summary>
        /// <param name="connection">一个有效的Sql连接</param>
        /// <param name="spName">使用"FOR XML AUTO"的存储过程的名字</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <param name="parameterValues">存储过程输入的值赋给这个对象数组</param>
        /// <returns>一个包含由命令产生结果集合的XmlReader</returns>
        XmlReader ExecuteXmlReader(OracleConnection connection, string spName, int commandTimeout, params OracleParameter[] parameterValues)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        ///     通过Sql命令(返回一个结果集合)来执行这个存储过程，
        ///     这个存储过程是为指定一个使用数据行列值作为存储过程参数值的连接字符串的Sql连接服务的。
        ///     这个方法为了发现存储过程(每一个第一次被调用的存储过程)的参数，它将会查询数据库, 并且按照参数的顺序给参数赋值。
        /// </summary>
        /// <param name="connection">一个有效的Sql连接</param>
        /// <param name="spName">使用"FOR XML AUTO"的存储过程的名字</param>
        /// <param name="parameterValues">存储过程输入的值赋给这个对象数组</param>
        /// <returns>一个包含由命令产生结果集合的XmlReader</returns>
        XmlReader ExecuteXmlReader(OracleConnection connection, string spName, params OracleParameter[] parameterValues)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        ///     通过Sql命令(返回一个结果集合)来执行这个存储过程，
        ///     这个存储过程是为指定一个使用数据行列值作为存储过程参数值的连接字符串的Sql事务服务的。
        ///     这个方法为了发现存储过程(每一个第一次被调用的存储过程)的参数，它将会查询数据库, 并且按照参数的顺序给参数赋值。
        /// </summary>
        /// <param name="transaction">一个有效的Sql事务</param>
        /// <param name="spName">存储过程的名字</param>
        /// <param name="parameterValues">把存储过程的输入参数赋给对象数组</param>
        XmlReader ExecuteXmlReader(OracleTransaction transaction, string spName, params OracleParameter[] parameterValues)
        {
            throw new NotImplementedException();
        }


        /// <summary>
        ///     执行一个Sql命令(返回一个结果集合并且不返回参数),这个命令是依附于指定的Sql事务
        /// </summary>
        /// <param name="transaction">一个有效的事务</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令。</param>
        /// <returns>包含由命令产生结果集合的XmlReader</returns>
        static XmlReader ExecuteXmlReader(OracleTransaction transaction, CommandType commandType, string commandText)
        {
            throw new NotImplementedException();
        }
        /// <summary>
        ///     执行一个Sql命令(返回一个结果集合并且不返回参数),这个命令是依附于指定的Sql事务
        /// </summary>
        /// <param name="transaction">一个有效的事务</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令。</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <returns>包含由命令产生结果集合的XmlReader</returns>
        static XmlReader ExecuteXmlReader(OracleTransaction transaction, CommandType commandType, string commandText, int commandTimeout)
        {
            throw new NotImplementedException();
        }
        /// <summary>
        ///     执行一个Sql命令(返回一个结果集合并且不返回参数),这个命令是依附于指定了提供了参数的Sql事务
        /// </summary>
        /// <param name="transaction">一个有效的Sql事务</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令。</param>
        /// <param name="commandParameters">执行命令的Sql参数数组</param>
        /// <returns>包含由命令产生结果集合的XmlReader</returns>
        static XmlReader ExecuteXmlReader(OracleTransaction transaction, CommandType commandType, string commandText, params OracleParameter[] commandParameters)
        {
            throw new NotImplementedException();
        }
        /// <summary>
        ///     执行一个Sql命令(返回一个结果集合并且不返回参数),这个命令是依附于指定了提供了参数的Sql事务
        /// </summary>
        /// <param name="transaction">一个有效的Sql事务</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令。</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <param name="commandParameters">执行命令的Sql参数数组</param>
        /// <returns>包含由命令产生结果集合的XmlReader</returns>
        static XmlReader ExecuteXmlReader(OracleTransaction transaction, CommandType commandType, string commandText, int commandTimeout, params OracleParameter[] commandParameters)
        {
            throw new NotImplementedException();
        }
        /// <summary>
        ///     执行一个Sql命令(返回一个结果集合并且不含有参数),这个命令是依附于指定的Sql连接
        /// </summary>
        /// <param name="connection">一个有效的Sql连接</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)</param>
        /// <param name="commandText">存储过程的名字或者是使用"FOR XML AUTO"的T-SQL命令。</param>
        /// <returns>一个包含由命令产生结果集合的XmlReader</returns>
        static XmlReader ExecuteXmlReader(OracleConnection connection, CommandType commandType, string commandText)
        {
            throw new NotImplementedException();
        }
        /// <summary>
        ///     执行一个Sql命令(返回一个结果集合并且不含有参数),这个命令是依附于指定的Sql连接
        /// </summary>
        /// <param name="connection">一个有效的Sql连接</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)</param>
        /// <param name="commandText">存储过程的名字或者是使用"FOR XML AUTO"的T-SQL命令。</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <returns>一个包含由命令产生结果集合的XmlReader</returns>
        static XmlReader ExecuteXmlReader(OracleConnection connection, CommandType commandType, string commandText, int commandTimeout)
        {
            throw new NotImplementedException();
        }


        /// <summary>
        ///     执行一个Sql命令(返回一个结果集合并且不返回参数),这个命令是依附于指定了连接字符串的数
        /// </summary>
        /// <param name="connection">一个有效的Sql连接</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)</param>
        /// <param name="commandText">存储过程的名字或者使用"XML AUTO"的T-SQL命令。</param>
        /// <param name="commandParameters">用于执行命令的Sql参数数组</param>
        /// <returns>一个包含由命令产生结果集合的XmlReader</returns>
        static XmlReader ExecuteXmlReader(OracleConnection connection, CommandType commandType, string commandText, params OracleParameter[] commandParameters)
        {
            throw new NotImplementedException();
        }
        /// <summary>
        ///     执行一个Sql命令(返回一个结果集合并且不返回参数),这个命令是依附于指定了连接字符串的数
        /// </summary>
        /// <param name="connection">一个有效的Sql连接</param>
        /// <param name="commandType">命令类型(存储过程，文本，等)</param>
        /// <param name="commandText">存储过程的名字或者使用"XML AUTO"的T-SQL命令。</param>
        /// <param name="commandTimeout">在终止执行命令的尝试并生成错误之前的等待时间</param>
        /// <param name="commandParameters">用于执行命令的Sql参数数组</param>
        /// <returns>一个包含由命令产生结果集合的XmlReader</returns>
        static XmlReader ExecuteXmlReader(OracleConnection connection, CommandType commandType, string commandText, int commandTimeout, params OracleParameter[] commandParameters)
        {
            throw new NotImplementedException();
        }
        #endregion
    }

    /// <summary>
    ///     这个SqlHelperParameterCache类提供一些函数，这些函数可以调节过程参数所占用的缓存大小,并且具有发现运行存储过程参数的能力。
    /// </summary>
    public sealed class SqlHelperParameterCache
    {
        #region private methods, variables, and constructors

        //由于这个类仅仅提供静态的方法，采用默认的private构造器，我们不用创建实例

        private static readonly Hashtable paramCache = Hashtable.Synchronized(new Hashtable());

        private SqlHelperParameterCache()
        {
        }

        /// <summary>
        ///     得到正在执行的存储过程的参数
        /// </summary>
        /// <param name="connection">一个有效的Sql连接对象</param>
        /// <param name="spName">存储过程的名字</param>
        /// <param name="includeReturnValueParameter">参数的值是否返回</param>
        /// <returns>一个发现的参数数组</returns>
        private static OracleParameter[] DiscoverSpParameterSet(OracleConnection connection, string spName,
                                                                bool includeReturnValueParameter)
        {
            if (connection == null) throw new ArgumentNullException("connection");
            if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");

            var cmd = new OracleCommand(spName, connection);
            cmd.CommandType = CommandType.StoredProcedure;

            connection.Open();
            OracleCommandBuilder.DeriveParameters(cmd);
            connection.Close();

            if (!includeReturnValueParameter)
            {
                cmd.Parameters.RemoveAt(0);
            }

            var discoveredParameters = new OracleParameter[cmd.Parameters.Count];

            cmd.Parameters.CopyTo(discoveredParameters, 0);

            // Init the parameters with a DBNull value
            // 用一个DBNull值来初始化参数
            foreach (OracleParameter discoveredParameter in discoveredParameters)
            {
                discoveredParameter.Value = DBNull.Value;
            }
            return discoveredParameters;
        }

        /// <summary>
        ///     拷贝在缓存中的Sql参数
        /// </summary>
        /// <param name="originalParameters"></param>
        /// <returns></returns>
        private static OracleParameter[] CloneParameters(OracleParameter[] originalParameters)
        {
            var clonedParameters = new OracleParameter[originalParameters.Length];

            for (int i = 0, j = originalParameters.Length; i < j; i++)
            {
                clonedParameters[i] = (OracleParameter)(originalParameters[i]).Clone();
            }

            return clonedParameters;
        }

        #endregion private methods, variables, and constructors

        #region caching functions

        /// <summary>
        ///     增加一个参数数组到缓存
        /// </summary>
        /// <param name="connectionString">一个有效的Sql连接字符串</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令</param>
        /// <param name="commandParameters">加到缓存中的Sql参数数组</param>
        public static void CacheParameterSet(string connectionString, string commandText,
                                             params OracleParameter[] commandParameters)
        {
            if (connectionString == null || connectionString.Length == 0)
                throw new ArgumentNullException("connectionString");
            if (commandText == null || commandText.Length == 0) throw new ArgumentNullException("commandText");

            string hashKey = connectionString + ":" + commandText;

            paramCache[hashKey] = commandParameters;
        }

        /// <summary>
        ///     从缓存中得到参数数组
        /// </summary>
        /// <param name="connectionString">一个有效的Sql连接字符串</param>
        /// <param name="commandText">存储过程的名字或者T-SQL命令</param>
        /// <returns>一个Sql参数数组</returns>
        public static OracleParameter[] GetCachedParameterSet(string connectionString, string commandText)
        {
            if (connectionString == null || connectionString.Length == 0)
                throw new ArgumentNullException("connectionString");
            if (commandText == null || commandText.Length == 0) throw new ArgumentNullException("commandText");

            string hashKey = connectionString + ":" + commandText;

            var cachedParameters = paramCache[hashKey] as OracleParameter[];
            if (cachedParameters == null)
            {
                return null;
            }
            else
            {
                return CloneParameters(cachedParameters);
            }
        }

        #endregion caching functions

        #region Parameter Discovery Functions

        /// <summary>
        ///     重新得到存储过程的参数
        /// </summary>
        /// <remarks>
        ///     这个方法将会为这个信息而查询数据库，然后把它存到缓存中，以等待相应的调用。
        /// </remarks>
        /// <param name="connectionString">一个有效的Sql连接字符串</param>
        /// <param name="spName">存储过程的名字</param>
        /// <returns>一个存储Sql参数的数组</returns>
        public static OracleParameter[] GetSpParameterSet(string connectionString, string spName)
        {
            return GetSpParameterSet(connectionString, spName, false);
        }

        /// <summary>
        ///     重新得到存储过程适当的Sql参数
        /// </summary>
        /// <remarks>
        ///     这个方法将会为这个信息而查询数据库，然后把它存到缓存中，以等待相应的调用。
        /// </remarks>
        /// <param name="connectionString">一个有效的Sql连接字符串</param>
        /// <param name="spName">存储过程的名字</param>
        /// <param name="includeReturnValueParameter">标示返回的参数值是否包括在结果中的一个布尔型的值</param>
        public static OracleParameter[] GetSpParameterSet(string connectionString, string spName,
                                                          bool includeReturnValueParameter)
        {
            if (connectionString == null || connectionString.Length == 0)
                throw new ArgumentNullException("connectionString");
            if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");

            using (var connection = new OracleConnection(connectionString))
            {
                return GetSpParameterSetInternal(connection, spName, includeReturnValueParameter);
            }
        }

        /// <summary>
        ///     重新得到存储过程适当的Sql参数
        /// </summary>
        /// <remarks>
        ///     这个方法将会为这个信息而查询数据库，然后把它存到缓存中，以等待相应的调用。
        /// </remarks>
        /// <param name="connection">一个有效的Sql连接对象</param>
        /// <param name="spName">存储过程的名字</param>
        /// <returns>一个Sql参数的数组</returns>
        internal static OracleParameter[] GetSpParameterSet(OracleConnection connection, string spName)
        {
            return GetSpParameterSet(connection, spName, false);
        }

        /// <summary>
        ///     重新得到存储过程适当的参数
        /// </summary>
        /// <remarks>
        ///     这个方法将会为这个信息而查询数据库，然后把它存到缓存中，以等待相应的调用。
        /// </remarks>
        /// <param name="connection">一个有效的Sql连接对象</param>
        /// <param name="spName">存储过程的名字</param>
        /// <param name="includeReturnValueParameter">标示返回的参数值是否包括在结果中的一个布尔型的值</param>
        /// <returns>一个Sql参数的数组</returns>
        internal static OracleParameter[] GetSpParameterSet(OracleConnection connection, string spName,
                                                            bool includeReturnValueParameter)
        {
            if (connection == null) throw new ArgumentNullException("connection");
            using (var clonedConnection = (OracleConnection)(connection).Clone())
            {
                return GetSpParameterSetInternal(clonedConnection, spName, includeReturnValueParameter);
            }
        }

        /// <summary>
        ///     重新得到存储过程适当的参数
        /// </summary>
        /// <param name="connection">一个有效的Sql连接对象</param>
        /// <param name="spName">存储过程的名字</param>
        /// <param name="includeReturnValueParameter">标示返回的参数值是否包括在结果中的一个布尔型的值</param>
        /// <returns>一个Sql参数的数组</returns>
        private static OracleParameter[] GetSpParameterSetInternal(OracleConnection connection, string spName,
                                                                   bool includeReturnValueParameter)
        {
            if (connection == null) throw new ArgumentNullException("connection");
            if (spName == null || spName.Length == 0) throw new ArgumentNullException("spName");

            string hashKey = connection.ConnectionString + ":" + spName +
                             (includeReturnValueParameter ? ":include ReturnValue Parameter" : "");

            OracleParameter[] cachedParameters;

            cachedParameters = paramCache[hashKey] as OracleParameter[];
            if (cachedParameters == null)
            {
                OracleParameter[] spParameters = DiscoverSpParameterSet(connection, spName, includeReturnValueParameter);
                paramCache[hashKey] = spParameters;
                cachedParameters = spParameters;
            }

            return CloneParameters(cachedParameters);
        }

        #endregion Parameter Discovery Functions
    }
}
